12

状況:
32 ビット用にコンパイルすると機能するが、gcc 4.6 で 64 ビット用にコンパイルすると失敗するコードがあります。問題を特定して標準を調べた後、なぜそれが 32 ビットで機能するのかがよくわかりません。誰かが何が起こっているのか説明できることを願っています。

コード (やや単純化され、興味深い部分に切り詰められています):

// tbl: unsigned short *, can be indexed with positive and negative values
// v: unsigned int
// p: unsigned char *
tmp = tbl[(v >> 8) - p[0]]; // Gives segfault when not compiled with -m32

-m32コードでコンパイルすると動作します。それなしでコンパイルする-m32と、segfault が発生します。segfault の理由は、64 ビット用にコンパイルさ(v >> 8) - p[0]れた場合に解釈され、 「否定的な」結果になると解釈されるためです。unsigned int

この質問によると、C99 標準は次のように述べています:
6.2.5c9:A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

このことから、unsignedマイナスunsignedは常にunsigned64 ビットの場合と一致する出力になるようです。これは、私が非常に奇妙だと思う 32 ビットの場合には発生しないようです。

32ビットの場合に何が起こっているのか、誰か説明できますか?

4

1 に答える 1

14

どちらの場合も、unsigned intがラップ アラウンドするため非常に大きな数値が得られますが、32 ビットの場合はポインター演算ラップ アラウンドするため、キャンセルされます。

ポインター演算を行うために、コンパイラーは配列インデックスをポインターと同じ幅にプロモートします。したがって、unsigned32 ビット ポインターの場合は、32 ビット ポインターの場合と同じ結果が得られintます。

例えば、

char *p = (char *) 0x1000;

// always points to 0x0c00
// in 32-bit, the index is 0xfffffc00
// in 64-bit, the index is 0xfffffffffffffc00
int r = p[(int) -0x400]; 

// depends on architecture
// in 32-bit, the index is 0xfffffc00 (same as int)
// in 64-bit, the index is 0x00000000fffffc00 (different from int)
int r = p[(unsigned) -0x400];
于 2012-09-05T14:00:06.390 に答える