{
char *a, *b;
printf("%lx\n",(b-a));
}
通常は動作しますが、実際には、32 ビットまたは 64 ビットのマシンで警告が表示されたり失敗したりすることは想像できません。しかし、それは ANSI C とサイズ認識のために適切なことでしょうか? Unix 以外や組み込みシステムを含む、可能なすべてのプラットフォームでこのコードが動作することを望みます。
b - a
は、自分の形式でptrdiff_t
印刷できるです。仕様セクションから6.5.6加法演算子:%td
printf
2つのポインターを減算する場合、両方が同じ配列オブジェクトの要素を指すか、配列オブジェクトの最後の要素の1つ先を指します。結果は、2つの配列要素の添え字の違いです。結果のサイズは実装によって定義され、その型(符号付き整数型)はヘッダーで
ptrdiff_t
定義されます。<stddef.h>
および関連する関数についてprintf
は、セクション7.19.6フォーマットされた入出力関数:
t
次の、、、、、、d
または変換指定子が、または対応する符号なし整数型引数に適用されることを指定i
します。または、次の変換指定子が引数へのポインターに適用されます。o
u
x
X
ptrdiff_t
n
ptrdiff_t
仕様をもう少し調べてみたところ、2つのポインターの違いがに収まらない可能性があることを示しているようですptrdiff_t
。この場合、動作は定義されていません。
J.2未定義の動作-2つのポインターを減算した結果は、タイプ(6.5.6)
のオブジェクトでは表現できません。ptrdiff_t
それが起こるかもしれない実装を想像することはできませんが。チェックインして、本当に確実にチェックインできるPTRDIFF_MIN
と思います。PTRDIFF_MAX
<stdint.h>
の結果は、と の両方が同じ char 配列の要素を指しているb - a
場合にのみ定義されます。すべてのオブジェクトは char 配列として再解釈できるため、この要件は、同じオブジェクトに属するバイトを指していると解釈することもできます。a
b
a
b
それ以外の場合、結果は未定義です。つまり、そのようなポインターを減算しようとすると、未定義の動作が発生します。
結果が定義されると、ptrdiff_t
型があります。ptrdiff_t
は typedef 名であり、その typedef 名の背後に隠れている型は実装定義です。ただし、型は署名されていることが知られています。
ptrdiff_t
また、ポインタが同じ配列の要素を指している場合でも、C 言語は、減算の結果を保持するのに十分な大きさを保証しないことに注意してください。ptrdiff_t
型が結果に対応するにはポインターが離れすぎている場合、動作は未定義です。
C99 でも特定のprintf
書式指定子がないptrdiff_t
ため、十分に大きな符号付き整数型に変換し、その型の書式指定子を使用する方がよいでしょう。
printf("%ld\n", (long) (b - a));
訂正: C99 には の長さ修飾子がありptrdiff_t
ます。C99 で結果を出力する適切な方法は次のようになります。
printf("%td\n", b - a);
t
は長さ修飾子であることに注意してください。取得する出力形式に応じて、 、 、 、または変換指定子d
とo
組み合わせるu
ことx
ができます。X
C89/90 では、十分に大きな符号付き型の使用に固執する必要があります。
PS 32 ビットまたは 64 ビットのマシンで失敗することは想像できないとおっしゃいました。実際、失敗することを想像する (または実際に失敗させる) ことは非常に簡単です。ptrdiff_t
32 ビット マシンの は通常 32 ビット タイプです。これは符号付きの型であるため、値の大きさを表すために使用できるのは 31 ビットのみです。より離れた 2 つのポインター (つまり、「距離」を表すのに 32 ビットが必要) を取得すると、 の結果b - a
はオーバーフローし、無意味になります。この失敗を防ぐptrdiff_t
には、32 ビット マシンでは少なくとも 33 ビットの署名が必要であり、64 ビット マシンでは少なくとも 65 ビットの署名ptrdiff_t
が必要です。実装は通常それを行いません。標準の「許可」を使用して、オーバーフロー時に未定義の動作を生成するだけです。
ですptrdiff_t
。差出人man stddef.h
:
ptrdiff_t 2つのポインターを減算した結果の符号付き整数型。
で印刷し%td
ます。
変数aとbを初期化していないため、コードは未定義の動作を示します。ただし、それ以外の場合、baのタイプはptrdiff_tであり、結果を含めるのに十分な大きさです。十分にモダンなCがある場合は、%txを使用してprintfできます。
%txを使用したくない場合は、結果を変換して、フォーマット指定子と実際に一致するようにする必要があります(偶然ではありません)。
printf("%lx", (unsigned long)(a-b));
たとえば、システムに32ビットのアドレス空間と32ビットのptrdiff_tがあり、64ビットの長さであると、printfが失敗することは考えられません。
ba の型はptrdiff_t です