C代码的行为与带阴影的结构声明相混淆

时间:2019-06-08 16:44:40

标签: c callstack shadowing

考虑以下C代码:

#include <stdio.h>

typedef struct {
    int a;
} TestType;

int main(){
    int an_int;
    TestType test;
    // printf("%d\n",test.a);
    {
        TestType test;
        test.a = 777;
        printf("offset: %lld\n", &test.a - &an_int); // maybe 2?
    }
    printf("%d\n", test.a);                        // should be garbage
    printf("offset: %lld\n", &test.a - &an_int);     // maybe 1?    
}

我声明一个TestType test,然后开始一个作用域并声明另一个TestType test,以第一个为对象。最后,print语句的预期输出是堆栈上的内容。使用gcc -o stack-allocate-weird stack-allocate-weird.c编译并运行,我得到输出:

offset: 1
777
offset: 1

因此,两个位置相同。此外,valgrind ./stack-allocate-weird没有报告错误。取消注释第一条打印语句,即可得到预期的输出:

-771776240
offset: 2
-771776240
offset: 1

如果我不是声明struct TestType而是声明int,而是代码按预期方式工作(最后一个print语句显示垃圾)。

我将代码放到服务器上并进行编译并得到:

offset: -2
0
offset: -1

哪个看起来也不错(我想堆栈朝相反的方向前进?)。另一方面,将我计算机上编译的二进制文件移到服务器上会得到原始的错误输出:

offset: 1
777
offset: 1 

这是gcc的已知错误吗?

我的计算机上的

gcc -v说(一堆其他东西):

gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)    

在服务器上显示:

gcc version 8.3.1 20190223 (Red Hat 8.3.1-2) (GCC)

所以这可能在两者之间的某个地方固定了吗?

1 个答案:

答案 0 :(得分:3)

我不认为这是GCC的错误。编译器将延迟外部TestType test的分配,直到需要它为止。这是第16行中的第二个printf()。内部的TestType test被放置在偏移量1处,就像您所看到的一样,直到其作用域关闭并且其内存再次可用。现在,需要外层的空间并占据相同的空间,从而为您提供内层的值和相同的偏移量。