3

私はC出力の質問に取り組んでいました:

#include<stdio.h>
int main()
{
   int a[][2][3]={0,1,2,3,4,5,6,7,8,9,10,11,12};
   int i=-1;
   int d;
   d=a[i++][++i][++i];
   printf("%d\n",d);
   return 0;
}

Ideone へのリンク: http://ideone.com/1oS9Un

実行時エラーを予期していましたが、驚くべきことに、コードは CodeBlocks、Dev C++、および Ideone で正常に動作しています。

私によると、すべてのメモリアドレスは実行時に次の式によってコンパイラによって解決されます: a[i][j][k]= ( (*(a+i)+j)+k) したがって、すべてのコンパイラは最初に内括弧 、次の内括弧など。

したがって、指定された行

d=a[i++][++i][++i];

次のように解決する必要があります。

d=*(*(*(a+i++)+ ++i)+ ++i)

http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm (注 2 を参照してください)

最も内側の括弧を最初に解決する必要があり、その値は a-1 で i が 0 になる必要があります。したがって、コンパイラによって特にマークされていないメモリにアクセスしようとすると、SIGSEGV エラーが発生するはずですが、それでもすべてに出力が表示されます。 3 つのコンパイラ。これを説明してください。

4

2 に答える 2

3

したがって、SIGSEGV エラーが発生するはずです

いいえ、すべきではありません。動作がundefinedの場合、何でも起こりえます。セグメンテーション違反の保証はありません。

PSコードの動作は未定義ですが、質問に記載されている以外の理由があります。実際の理由は、iシーケンス ポイント間で何度か変更を加えているためです。C FAQを参照してください。

于 2013-08-29T09:36:16.197 に答える
0

「配列の範囲を超えた場合、システムは実行時にセグメンテーション違反(別名メモリアクセス違反)でプロセスを終了する必要がある」と述べているC標準はどこにもありません。

この意味でC は安全ではありません。場合によっては機能し、他の機能では失敗する可能性のある誤ったコードを自由に記述できます。それは誤りだからです。標準は、間違ったときに何が起こるべきかを定義することを意図していません-何が正しいか、物事が正しいときに何が起こるか、そして(一般的に暗示的に)何が間違っているかを定義することを意図していますが、(繰り返します)何が間違っているかではありません物事が間違っているときに起こるべきです。これにより、実装に追加の (そしておそらく非常に不必要な) 制約が課せられます。

これが、未定義の動作という用語がある理由です。これは、C 標準のために造られたと私は信じています。「未定義」とは、カバーされていないことを行ったときに発生することです。これは、論理的な結果である場合もありますが、一貫性があるという保証はありません。

于 2013-08-29T09:48:05.013 に答える