#include <stdio.h>
void main() {
{
int x;
printf("%p\n", &x);
}
{
int x;
printf("%p\n", &x);
}
}
Run Code Online (Sandbox Code Playgroud)
我认为运行此命令将输出相同的内容两次。当它声明第一个变量时,它会递增堆栈指针,但会离开作用域,因此会递减它,然后第二次重复该过程,因此int x两次都将占用堆栈上的相同内存位置。
但是事实并非如此。堆栈指针不会递减,int x在两种情况下都将占用堆栈中的不同位置。实际上,int x即使范围已消失,第一个仍然可以访问。
#include <stdio.h>
void main() {
{
int x = 10;
printf("%p\n", &x);
}
{
int x = 25;
printf("%p\n", &x);
}
{
int x = 71;
printf("%p\n", &x);
int *p = &x;
printf("%i %i %i\n", *(p + 2), *(p + 1), *p);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么是这样?我有什么误会?
C标准甚至没有提到堆栈。不需要变量时,编译器可以自由地优化变量。C标准中绝对没有任何内容暗示打印输出不应相等或不相等。
在我的计算机上,这通过根据优化级别提供不同的输出来体现出来:
$ gcc c.c
/tmp$ ./a.out
0x7ffd8733c3ac
0x7ffd8733c3a8
/tmp$ gcc c.c -O3
/tmp$ ./a.out
0x7fff4e91544c
0x7fff4e91544c
Run Code Online (Sandbox Code Playgroud)
实际上,即使第一个“ int x”的范围已消失,仍然可以访问。
访问超出范围的变量会导致未定义的行为,这意味着任何事情都可能发生。这包括程序按预期工作的情况。
这是您的第二个代码段采用不同优化的输出:
/tmp$ ./a.out
0x7ffd4df94864
0x7ffd4df94860
0x7ffd4df9485c
10 25 71
/tmp$ gcc c.c -O3
/tmp$ ./a.out
0x7ffc30b4e44c
0x7ffc30b4e44c
0x7ffc30b4e44c
0 0 71
Run Code Online (Sandbox Code Playgroud)
当您根据优化级别获得不同的行为时,几乎有100%的迹象表明您的程序中有某些东西会导致未定义的行为。您在编译器中遇到错误的机会非常小。除了这两个原因外,我想不出其他任何可能的原因。
作为一个实际问题,当一个堆栈确实存在(如Broman的回答指出,对于一个堆栈存在没有要求,尽管是要支持递归要求)编译器通常会生成代码,调整堆栈指针只在函数一次进入,然后再次退出,即使函数中存在子范围限制单个变量的生存期。
如果您习惯于手工编写汇编语言,这可能看起来很奇怪。最基本的原因是,这意味着驻留在堆栈上的每个变量都有一个“堆栈插槽”,在整个函数中的位置固定,这为编译器在移动机器指令以进行优化方面提供了最大的灵活性。
| 归档时间: |
|
| 查看次数: |
129 次 |
| 最近记录: |