3

ポインター演算の場合、整数は自動的に符号付きバリアントに変換されますか? はいの場合、なぜですか?

私がそうするとしましょう

int *pointer; 
int *pointerdiff;
unsigned int uiVal = -1;

pointerdiff = pointer + uiVal // Pointer will contain valid address here.

ここで、pointer は int へのポインターであり、uiVal は -1 に初期化されています。次に、ポインターのアドレスが 4 減っていることがわかりました。-1 の符号なし値がここで考慮されないのはなぜですか?

4

3 に答える 3

8

ポインタがオーバーフローしているようです。

計算してみましょう。32 ビット マシンを使用していて、ポインタが に初期化されているとします0x 12 34 56 78。次に、unsigned int 変数を に初期化します。-1これは0x FF FF FF FFです。これは符号なし整数であるため、-1はオーバーフローし、実際には を表し4 294 967 295ます。

ポインタは整数 ( int*) を指しているため、各インクリメントは実際にはアドレスをsizeof intでインクリメントします。これは、標準の x86 マシンでは 4 です。したがって、実際に追加しています0x 03 FF FF FF FC(これは です0x FF FF FF FF * 4)。

では、2 つを足し合わせてみましょう。

  0x 00 12 34 56 78
+ 0x 03 FF FF FF FC
-------------------
  0x 04 12 34 56 74

もちろん、これはオーバーフローします。なぜなら、現在 40 ビットの値があり、ポインターは 32 ビットであり、その量の情報しか保持できないからです。したがって04、開始時に を失います。これにより、0x 12 34 56 74が得られ0x 12 34 56 78 - 4ます。

于 2010-04-05T13:07:25.003 に答える
3

はい、整数オペランドは昇格されます。しかし、それはここでは問題ではありません。符号なしタイプの場合uiValはできません。-1おそらくあなたがした

unsigned int uiVal = -1;
pointer + uiVal ...

しかし、それは同じことをします

pointer + UINT_MAX ...

また、ポインターが保持できるアドレス範囲がこの追加に対応できない場合、未定義の動作が発生する可能性があります。規格は次のように述べています5.7/4

これらの演算子の目的上、非配列オブジェクトへのポインターは、要素の型としてオブジェクトの型を持つ長さ 1 の配列の最初の要素へのポインターと同じように動作します。

整数型の式をポインタに加算または減算すると、結果はポインタ オペランドの型になります。ポインターオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、[...] . ポインターオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しませんそれ以外の場合、動作は未定義です。

つまり、結果ポインターが同じ配列内にない場合、または末尾の 1 つ後ろにある場合、または存在するがオーバーフローによって存在する場合、動作は未定義です。

于 2010-04-05T13:04:19.737 に答える
0

右側のオペランドが ptrdiff_t 型にキャストされていると思いますが、これは符号付きのようです。

于 2010-04-05T13:04:45.040 に答える