考虑以下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报告没有错误。取消对第一个print语句的注释将提供预期的输出:
-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)

所以也许在这两者之间的某个地方解决了?

最佳答案

我不认为这是GCC的缺陷。编译器正在延迟外部TestType test的分配,直到需要它为止。这是第16行的第二个printf()。内部的TestType test被放置在偏移量1处,就像您观察到的那样,直到它的作用域关闭并且它的内存再次释放。现在需要外部的,占用相同的空间,给你内部的值和相同的偏移量。

10-07 19:11