关于C语言中堆栈分配的问题
下面的代码段是有意访问关于C语言中堆栈分配的问题,c,memory-management,stack,C,Memory Management,Stack,下面的代码段是有意访问t[4]之后的下一个sizeof(int)字节,因此我知道这里出现了错误。我只是在做一个实验,看看编译器如何处理堆栈分配 int t[5], i; for (i = 0; i <= 5; i++) { t[i] = 0; } intt[5],i; 对于(i=0;i访问t[5]是一种未定义的行为。最后一项是t[4](t[0],t[1],t[2],t[3],t[4])没有t[5] 通过未定义的行为,任何事情都可能发生。它可能会给出预期的结果或完全混乱 我的问题是
t[4]
之后的下一个sizeof(int)字节,因此我知道这里出现了错误。我只是在做一个实验,看看编译器如何处理堆栈分配
int t[5], i;
for (i = 0; i <= 5; i++) {
t[i] = 0;
}
intt[5],i;
对于(i=0;i访问t[5]
是一种未定义的行为。最后一项是t[4]
(t[0],t[1],t[2],t[3],t[4]
)没有t[5]
通过未定义的行为,任何事情都可能发生。它可能会给出预期的结果或完全混乱
我的问题是,为什么会有这种不同的行为
正如我之前所写的,你不能期望任何东西。即使你在同一台机器上多次尝试也可能得到另一个结果。你正在处理未定义的行为。编译器不需要按顺序排列自动变量(如源代码中所示)。其中一些可能位于寄存器中,或者它们可能以不同的方式排序,例如,如果偏移量较小,则更便宜
这种要求只存在于结构的成员(成员之间有任意填充)
有填充物吗
是的,编译器将遵守每种类型的对齐要求,并相应地放置变量
顺序是否总是与源代码中的顺序相同
不,但这是许多漏洞攻击所依赖的。缓冲区溢出可能会覆盖相邻的变量并危及整个程序的执行。另一个人说,为什么从标准的角度来看,您会出现这种行为,我将说明编译优化和执行代码后可能发生的情况
第一个:循环可能展开并执行6次:
t[0] = 0;
t[1] = 0;
t[2] = 0;
t[3] = 0;
t[4] = 0;
t[5] = 0;
i = 6;
这是允许优化的,这就是可能发生的。更多:如果以后不使用i
,则可以将其完全删除
Second:编译器可以在寄存器中保留i
,而不进行任何堆栈分配
第三个:它可以在堆栈上以任何顺序放置变量。对于变量在内存中的保存顺序(以及它们的位置)没有实际要求
如何知道发生了什么?查看生成的程序集。这是知道发生了什么的唯一方法
顺便说一句:无限循环并不总是发生在Windows上。事实上,我无法强迫您的代码逐字成为无限循环。C
和C++之间有区别。请不要将这两个问题都加上标签。“我认为堆栈分配应该以相同的方式发生。”-你为什么这么认为?这完全是一个实现细节,而不是语言定义的任何方式。你为什么认为无休止循环的原因是赋值修改i
?它也可能是编译器知道i你在不同平台上使用不同的编译器,从而定义了不同的行为d behavior=任何事情都可能发生。您可以看出,在这两种情况下,任何事情都确实发生了,因此该行为符合预期(没有预期的行为)调查为什么不确定的行为在特定的系统中导致特定的结果,在特定的时间点,这只是没有意义的练习。@ GARF365:C++标准不能解释它,但是肯定不是没有什么可以。@本杰明德利,是的,但是为什么?为什么我应该知道如果我做了不确定的事情会发生什么?lfawi:我不知道。也许你对编译器的工作方式感兴趣。@BenjaminLindley它不是关于编译器如何工作的。它是关于编译器如何处理你不应该使用的东西:)它甚至不应该被记录,如果编译器在下一版本中改变这种行为,你甚至不能在法庭上向编译器提起诉讼:)@AlexandruPele也许问题只是。。。措辞不好。在我看来,你们的要求是方向性的,但适用于变量和“相同的代码,不同的编译器,不同的平台”范围。谢谢!我没有真正考虑编译器优化或栈中的顺序不一定相同的事实。