5
{
  char *a, *b;

  printf("%lx\n",(b-a));
}

通常は動作しますが、実際には、32 ビットまたは 64 ビットのマシンで警告が表示されたり失敗したりすることは想像できません。しかし、それは ANSI C とサイズ認識のために適切なことでしょうか? Unix 以外や組み込みシステムを含む、可能なすべてのプラットフォームでこのコードが動作することを望みます。

4

5 に答える 5

22

b - aは、自分の形式でptrdiff_t印刷できるです。仕様セクションから6.5.6加法演算子%tdprintf

2つのポインターを減算する場合、両方が同じ配列オブジェクトの要素を指すか、配列オブジェクトの最後の要素の1つ先を指します。結果は、2つの配列要素の添え字の違いです。結果のサイズは実装によって定義され、その型(符号付き整数型)はヘッダーでptrdiff_t定義されます。<stddef.h>

および関連する関数についてprintfは、セクション7.19.6フォーマットされた入出力関数

t次の、、、、、、dまたは変換指定子が、または対応する符号なし整数型引数に適用されることを指定iします。または、次の変換指定子が引数へのポインターに適用されます。ouxXptrdiff_tnptrdiff_t

仕様をもう少し調べてみたところ、2つのポインターの違いがに収まらない可能性があることを示しているようですptrdiff_t。この場合、動作は定義されていません。

J.2未定義の動作-2つのポインターを減算した結果は、タイプ(6.5.6)
のオブジェクトでは表現できません。ptrdiff_t

それが起こるかもしれない実装を想像することはできませんが。チェックインして、本当に確実にチェックインできるPTRDIFF_MINと思います。PTRDIFF_MAX<stdint.h>

于 2009-10-29T18:33:45.727 に答える
12

の結果は、と の両方が同じ char 配列の要素を指しているb - a場合にのみ定義されます。すべてのオブジェクトは char 配列として再解釈できるため、この要件は、同じオブジェクトに属するバイトを指していると解釈することもできます。abab

それ以外の場合、結果は未定義です。つまり、そのようなポインターを減算しようとすると、未定義の動作が発生します。

結果が定義されると、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は長さ修飾子であることに注意してください。取得する出力形式に応じて、 、 、 、または変換指定子do組み合わせるuことxができます。XC89/90 では、十分に大きな符号付き型の使用に固執する必要があります。

PS 32 ビットまたは 64 ビットのマシンで失敗することは想像できないとおっしゃいました。実際、失敗することを想像する (または実際に失敗させる) ことは非常に簡単です。ptrdiff_t32 ビット マシンの は通常 32 ビット タイプです。これは符号付きの型であるため、値の大きさを表すために使用できるのは 31 ビットのみです。より離れた 2 つのポインター (つまり、「距離」を表すのに 32 ビットが必要) を取得すると、 の結果b - aはオーバーフローし、無意味になります。この失敗を防ぐptrdiff_tには、32 ビット マシンでは少なくとも 33 ビットの署名が必要であり、64 ビット マシンでは少なくとも 65 ビットの署名ptrdiff_tが必要です。実装は通常それを行いません。標準の「許可」を使用して、オーバーフロー時に未定義の動作を生成するだけです。

于 2009-10-29T18:35:13.080 に答える
5

ですptrdiff_t。差出人man stddef.h

ptrdiff_t
              2つのポインターを減算した結果の符号付き整数型。

で印刷し%tdます。

于 2009-10-29T18:33:23.623 に答える
2

変数abを初期化していないため、コードは未定義の動作を示します。ただし、それ以外の場合、baのタイプはptrdiff_tであり、結果を含めるのに十分な大きさです。十分にモダンなCがある場合は、%txを使用してprintfできます。

%txを使用したくない場合は、結果を変換して、フォーマット指定子と実際に一致するようにする必要があります(偶然ではありません)。

printf("%lx", (unsigned long)(a-b));

たとえば、システムに32ビットのアドレス空間と32ビットのptrdiff_tがあり、64ビットの長さであると、printfが失敗することは考えられません。

于 2009-10-29T18:32:22.867 に答える
2

ba の型はptrdiff_t です

于 2009-10-29T18:36:07.393 に答える