为什么这个内存引用了segfault?

时间:2016-02-02 08:37:56

标签: c memory-management

double fun(int i)
{
 volatile double d[1] = {3.14};
 volatile long int a[2];
 a[i] = 1073741824;
 return d[0];
}

有趣(0)➙3.14

有趣(1)➙3.14

有趣(2)➙3.1399998664856

有趣(3)➙2.00000061035156

有趣(4)➙3.14,然后分段错误

有人可以向我解释在这个例子中发生了什么以及为什么在调用func(2)时不会出现segfault? 为什么返回值不总是3.14?

1 个答案:

答案 0 :(得分:5)

您声明一个包含2个条目的数组:

volatile long int a[2];

然后使用索引访问此数组:

a[i] = 1073741824;

由于C中的数组索引从0开始,任何大于1的索引都会产生未定义的行为。

在您的程序中,您正在使用索引i=2i=3i=4调用该函数。

这些函数调用中的每一个都独立地产生未定义的行为。

未定义的行为意味着任何都可能发生。

您只在fun(4)遇到分段错误这一事实仅仅是巧合。

补充:

免责声明:以下分析并不意味着在每个平台上,甚至在每次执行时都会出现相同的行为;它只是为了解释观察到的“奇数”返回值。

  • 1073741824的4字节十六进制值为0x40000000
  • 3.14的8字节十六进制值为0x40091EB851EB851F(符合IEEE 754)
  • 通过将0x40000000写入a[2],您已覆盖d[0]的8字节值中的4个最低有效字节(不会导致分段错误),从而将其更改为{ {1}}到0x40091EB851EB851F,代表({75})浮点值0x40091EB840000000
  • 通过将3.1399998664856写入0x40000000,您已覆盖a[3]的8字节值中的4个最重要字节(不会导致分段错误),从而将其更改为{ {1}}到d[0],代表({75})浮点值0x40091EB851EB851F