C:数组初始化错误的奇怪行为


#include <stdio.h>
#include <stdlib.h>
int main() {
int step;
double position[4];
position[0] = 1;
for (step = 1;step<=4;step++){
position[step] = 99;
}
return 0;
}

可以编译而不会出错,生成的程序可以运行。

然而

#include <stdio.h>
#include <stdlib.h>
int main() {
int step;
double position[3];
position[0] = 1;
for (step = 1;step<=3;step++){
position[step] = 99;
}
return 0;
}

也可以编译,但程序无法运行:错误Abort trap: 6

在上述两种情况下,(错误)初始化的数组的大小比我在 for 循环中填写的大小小 1。但是,为什么43在这里有所作为呢?

现在,更有趣的是,

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
int main() {
int step;
double position[4];
position[0] = 1;
position[1] = 99;
position[2] = 99;
position[3] = 99;
position[4] = 99;
return 0;
}

甚至无法编译(错误为array index 4 is past the end of the array (which contains 4 elements)。那么为什么 for 循环在这里会有所不同呢?

在第三种情况下,编译器会提醒您越界访问。该标准不要求它抱怨,但它这样做了。

对于前两种情况,没有必要考虑正在发生的事情。你说第一个程序运行良好。它没有 - 它有一个 UB。

对于你关于3和4如何改变任何东西的问题,它可能取决于堆栈帧的布局方式。由于对齐方式差异,退货地址可能在一种情况下被弄乱,但在另一种情况下不会。您必须查看生成的程序集文件,以了解实际出了什么问题。

此 https://godbolt.org/g/gqz39q 表明,如果您将数组大小设置为 3,它将position放在%rbp - 32处,step放在%rbp - 4处。所以万一当你写position[3]时,step被覆盖了(我不想考虑正在写什么)。

当您将position的大小设为 4 时,它会将step置于%rbp - 4position置于%rbp - 48。现在你写信给position[4]%rbp - 48 + 4 * 8 = %rbp - 16.这将写入%rbp - 8.所以%rbp - 4(step)没有改变。

长话短说,填充在案例 1 中拯救了您,但在案例 2 中没有。

PS:同样,这是特定于所选编译器gcc 6.2与O0优化级别。在您的情况下,原因可能完全不同。

C 语言中没有提到任何内容可以阻止您编写访问越界内存的代码,标准只是清楚地提到任何这样做的尝试都会导致未定义的行为。

任何诊断,如果提供由编译器自行决定,可能与提供的编译器选项相关联,标准没有提到这一点的要求。

例如,对于某些编译器,最后一个代码段编译得很好(并且也会收到运行时错误)。

注1:在显示的代码段中,语句不是初始化,而是赋值

注意2:我稍微修改了代码,但所做的无效访问是相同的

#include <stdio.h>
int main(void) {
//int step;             // remove unused variable warning
double position[4];
position[0] = 1;
position[1] = 99;
position[2] = 99;
position[3] = 99;
position[4] = 99;
(void) position;          // suppress unused variable warning
return 0;
}

相关内容

  • 没有找到相关文章

最新更新