c-为什么GCC为不同作用域中的本地联合分配单独的堆栈空间



考虑以下代码:

#include <stdlib.h>
#ifndef TRY
#define TRY struct
#endif
TRY testme
{
  int one;
  int two;
  char three;
  int four;
};
int
main (void)
{
  {
    volatile TRY testme one;
    one.one = 2;
    one.three = 7;
  }
  {
    volatile TRY testme twos;
    twos.one = 3;
  }
  {
    volatile TRY testme one;
    one.one = 4;
  }
  {
    volatile TRY testme twos;
    twos.one = 5;
  }
  {
    volatile TRY testme twos;
    twos.one = 6;
  }
  {
    volatile TRY testme twos;
    twos.one = 6;
  }
  return EXIT_SUCCESS;
}

按照x86的原样编译(意味着testme是一个结构),编译器为main分配的堆栈大小为16字节。

$ gcc -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main
16 main

然而,使用定义为并集的TRY编译(意味着testme是并集),编译器为main分配的堆栈大小为32字节:

$ gcc -DTRY=union -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main

此外,在其他作用域中定义的结构/联合的任何其他实例在使用联合时都会产生更大的堆栈分配,但在用作结构时不会扩大堆栈分配。

现在,这是没有意义的——联合应该占用更少的堆栈空间,如果有的话,而不是更多,那么就是一个具有相同字段的结构!

即使在不同的作用域中,GCC似乎也将并集视为同时使用,但对结构却不这样做。

更多澄清:

  1. volatile用于阻止编译器优化分配。释放volatile和不进行优化的编译会产生相同的结果。

  2. 即使testme是一个将并集作为成员之一的结构,也会观察到相同的行为。换句话说,只要结构的一个成员是GCC的联合,就足以进行单独的堆栈分配。

  3. 编译器是gcc 4.4.3版(Ubuntu 4.4.3-4ubuntu5),但用于其他体系结构的其他gcc版本显示出相同的行为。

  4. checkstack.pl只是在objdump输出中搜索用于分配堆栈(sub到堆栈指针)的指令。

我的问题:

  1. GCC为什么要这样做?这是一个错误,还是这种行为有原因
  2. 假设这不是一个bug,有没有一种方法可以解决这个问题,并强制GCC为stuts分配与union相同的堆栈

澄清:我的问题不是为什么结构或并集的大小看起来比其部分的大小更大。我知道原因是为了对齐而填充。我的问题是,编译器为并集的不同实例分配多个堆栈帧,即使它们是在不同的作用域中定义的,而对于具有相同字段的结构,它不应该也确实不会这样做。

谢谢!

显然,至少有人试图放松gcc对工会的严格别名偏执。

您可能希望确保从中编译的gcc源应用了以下补丁或等效补丁:http://codereview.appspot.com/4444051/

它看起来像Int.的填充和基本默认大小定义

在32位中,内存映射将为:一(2字节)两个(2字节)三(1字节)(1字节)填充四(2字节)

总计-8字节。

在64位中,它将是:一(4字节)两个(4字节)三(1字节)(3字节填充)四(4字节)

总计-16字节。

如果将"int"更改为"short int",则内存看起来会有所不同。

相关内容

最新更新