2016-10-18 5 views
1

32ビットのUbuntu仮想マシン上のコード以下しようとしました:アレイのメモリアドレスが常に増加しないのはなぜですか?

static int a[0x1f0fff]; 
cout << &a[0x600000] << endl; 
cout << &a[0x800000] << endl; 
cout << &a[0x8fff00000] << endl; 

0x984a140 
0xa04a140 
0x7c4a140 

アドレスは増加し続けていないことを本当に混乱し。

アレイはヒープに配置されており、何が仮想メモリアドレスです。仮想メモリ空​​間を超えているからですか?

さらに、another answerによれば、最後の2つのラインコードは、に割り当てられていないメモリの一部にインデックスするです。なぜsegfaultは報告されていないのですか?

+3

「なぜセグメンテーションは報告されていませんか? Segfaultsは、プログラムが割り当てられていないメモリにアクセスすると発生します。 segfaultはあなたのプログラムが大丈夫であるとは限りません。プログラムが間違っているとすぐにクラッシュする必要はありません。 – xaxxon

+0

保証はありません。これは未定義の動作です。 –

+0

誰かがすでに答えを知っているはずだと思うので、質問をdownvoteしないでください。あなたが質問をdownvote場合は、理由についてのコメント。 – xaxxon

答えて

3

16進数の表記は、派手ではありませんが、難読化以外のものではありません(ただし、16進リテラルの型推論ルールはデナリリテラルとは異なります)。

コードの動作はで、定義されていません。と思われるかもしれませんが、おそらくそうではありません。 &a[0x600000]が実際にそれのアドレスを取る前にa番目の要素間接参照存在しない(0x600000)にしようとしていないこと

注意。コンパイラは式をa + 0x600000として評価する必要があります。 しかし、

aの配列内の要素ではないアドレス、またはその配列の末尾を超えるアドレスへのポインタを設定することは、未定義の動作です。したがって、コンパイラは何も出力することはできません。

+0

ありがとうございます。私は論理を得た。未定義の動作は不合理です。しかし、 '#define offsetof(TYPE、MEMBER)((size_t)&((TYPE *)0) - > MEMBER)'というコードは何度も使われています。これでアドレス0を使用できますか? – heLomaN

+1

@heLomaN:確かにC(とCの慣用句)でもOKですが、C++を思い出すことはできません。多分質問としてそれを頼んでください。 – Bathsheba

+0

@heLomaN: 'offsetof'はあなたの実装の一部であり、自分で書き込むことができないためでなければなりません。実装の一部として、あなたの実装はこのように '(TYPE *)0'を使用することがあります。別の一般的な実装は '#define offsetof __builtin_offsetof'です。 – MSalters

2

未定義の動作はsegfaultではありません。あなたは希望のsegfaultです。時々あなたは鼻の悪魔を得る。

なぜこの特定の動作ですか? 32ビット符号なし数学mod 2^32。起こることは保証されていませんが、コンパイルされた結果がここでやっていることは間違いありません。

+0

ありがとうございます。私は未定義のコードを試してはいけません。しかし、数学は正しくない、0xa04a140 + 0x8fff00000 - 0x800000!= 0x7c4a140。定義されていない可能性があります。 – heLomaN

+0

@helo mod 2^32は 'sizeof(int)'と同じです。ポインタの算術演算は、ここで '+ sizeof(int)'をそれぞれの '+ 1 'に追加します。 – Yakk

1

また、別の答えによれば、最後の2つのラインコードは、割り振られていないメモリの一部に索引付けされています。なぜsegfaultは報告されていないのですか?

アレイのアウトオブバウンドは未定義の動作です。何かが起こる可能性があります。つまり、セグメンテーションが保証されていないことを意味します - 次回に発生する可能性がありますなぜそれが未定義と呼ばれているのか)。

関連する問題