9

配列の境界を離れない限り、ポインター演算が定義されていることを常に読んでいます。これが何を意味するのか完全に理解できているかどうか確信が持てず、少し心配していました。したがって、この質問。

配列の先頭へのポインターから始めるとします。

int *p = (int*) malloc(4 * sizeof(int));

ここで、配列の境界外にある 2 つの新しいポインターを作成します。

int *q = p + 10;
int *r = p - 2;

ポインタq-10q-9、 ...、r+2r+3などはすべて、配列の境界内にあります。それらは有効ですか?たとえば、?と同じ結果が得られることがr[3] 保証されています。p[1]

私はいくつかのテストを行いましたが、動作します。しかし、これが通常の C 仕様でカバーされているかどうかを知りたいです。具体的には、Visual Studio 2010、Windows を使用しており、ネイティブ C (C++ ではない) でプログラミングしています。私はカバーされていますか?

4

3 に答える 3

9

あなたがしていることは、使用している実装と最も一般的な実装で機能しますが、C に準拠していません。クリスが引用したように、

§6.5.6/8: ポインタ オペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は未定義です

未定義であるという事実は、おそらく将来ますます重要になるでしょう。より高度な静的解析により、コンパイラはランタイム コストを発生させることなく、この種のコードを致命的なエラーに変えることができます。

ちなみに、同じ配列内にないポインターを未定義で減算する歴史的な理由は、セグメント化されたメモリです (16 ビット x86 を考えてください。これに精通している人は、「大規模な」メモリ モデルを考えたいと思うでしょう)。ポインタにはセグメントとオフセット コンポーネントが含まれる場合がありますが、コンパイラはオフセット コンポーネントだけで演算を実行して、ランタイム コストを回避できます。これにより、差の「上位部分」が失われるため、同じセグメントにないポインター間の算術演算が無効になります。

于 2012-08-24T03:51:13.370 に答える
5

C11 標準、§6.5.6/8 によると (コンテキストのために最初の部分を入れました):

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

したがって、配列の外側にあり、最後の 1 つを超えていない結果は、未定義の動作です。

于 2012-08-24T03:51:14.210 に答える
-1

「はい」あなたが言及した条件は仕様に含まれています。

    int *r = p - 2;

r が配列 p の境界外にある場合、評価の結果、位置が r に割り当てられます。p のアドレスの前後の 2 int 位置です。

`r[3]` は単に r のアドレスの後の「4 番目」の int 位置です
于 2012-08-24T06:07:41.627 に答える