期待SIGSEGV,但正常工作

时间:2013-08-29 09:34:32

标签: 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;
}

指向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错误,因为我们试图访问未经编译器特别标记的内存,仍然输出是显示在所有三个编译器中。请解释一下。

2 个答案:

答案 0 :(得分:3)

  

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

不,我们不应该。如果行为是undefined,则任何事情都可能发生。不保证会出现段错误。

P.S。代码的行为是未定义的,但原因不在于问题中所述的原因。实际原因是您在序列点之间多次修改i。请参阅C FAQ

答案 1 :(得分:0)

没有C标准在任何地方声明“如果你越过数组的边界,那么系统必须在运行时以分段错误(也就是内存访问冲突)终止进程”。

从这个意义上说,

不安全。您可以自由编写可能有时起作用的错误代码,而在其他代码中则失败,因为它是错误的。该标准并非旨在定义出错时应该发生的事情 - 它旨在定义什么是正确的,什么会在事情正确时发生,以及(通常暗示)什么是错误但是(再次)不是在出现问题时会发生什么。这将对实现产生额外的(并且可以说是非常不必要的)约束。

这就是为什么我们有术语未定义的行为,我认为这是为C标准创造的。 “未定义”是指当你做一些未被覆盖的事情时会发生的事情 - 它有时可能仍然是一个逻辑结果,只是你无法保证它是一致的。