C 期待SIGSEGV,但正在正常工作

C 期待SIGSEGV,但正在正常工作,c,runtime-error,operator-precedence,C,Runtime Error,Operator Precedence,我正在研究一个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; } 应解决为: d=*(*(*(a+i++)+ ++i)+ ++i) 也是,, (请参阅注2) 应该首先解析最里面的括号,它的值应该是a

我正在研究一个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;
}
应解决为:

d=*(*(*(a+i++)+ ++i)+ ++i)
也是,, (请参阅注2)

应该首先解析最里面的括号,它的值应该是a-1,i变成0。因此,当我们试图访问没有被编译器特别标记的内存时,我们应该得到一个SIGSEGV错误,仍然在所有三个编译器中显示一个输出。请解释一下

因此,我们应该得到一个SIGSEGV错误

不,我们不应该。如果这种行为是错误的,任何事情都有可能发生。不能保证会发生故障


另外,您的代码行为未定义,但原因与问题中所述的不同。实际原因是在序列点之间多次修改
i
。请参阅。

没有一个C标准规定“如果您超出了数组的界限,那么系统必须在运行时以分段错误(又称内存访问冲突)终止进程”

C在这个意义上是不安全的。您可以自由编写错误的代码,这些代码有时可能会运行,但有时会失败,因为它是错误的。该标准的目的不是定义当你犯错时应该发生什么——它旨在定义什么是对的,什么是对的,什么是对的,什么是错的(通常是含蓄的),但(再次)不是什么是错的。这将给实现带来额外的(可以说是非常不必要的)约束


这就是为什么我们有“未定义行为”这个术语,我相信它是为C标准创造的。“未定义”是指当你做了一些未涵盖的事情时会发生的情况——有时这可能仍然是一个合乎逻辑的结果,只是你不能保证它是一致的。

但为什么会有这种未定义的行为?
d=*(*(*(a+i++)+ ++i)+ ++i)