为什么GCC为不同范围内的本地联合分配单独的堆栈空间?

时间:2012-02-22 07:43:19

标签: c gcc stack stack-size

请考虑以下代码:

#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定义为union(意思是testme是一个联合)编译,编译器为main分配的堆栈大小为32字节:

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

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

现在,这没有意义 - 联合应该占用更少的堆栈空间,如果有的话,不要更多,然后是具有相同字段的结构!

似乎GCC将工会视为同时使用,即使在不同的范围内,但结构也不同。

更多澄清:

  1. volatile用于阻止编译器优化分配。在没有优化的情况下松开volatile并进行编译会产生相同的结果。

  2. 即使testme是具有union作为其中一个成员的结构,也会观察到相同的行为。换句话说 - 结构的一个成员就是GCC的并集就可以进行单独的堆栈分配就足够了。

  3. 编译器是gcc版本4.4.3(Ubuntu 4.4.3-4ubuntu5),但其他架构的其他GCC版本显示了相同的行为。

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

  5. 我的问题:

    1. 为什么海湾合作委员会这样做?这是一个错误还是有这种行为的原因?
    2. 假设这不是一个错误,是否有办法解决这个问题并迫使GCC为与工会相同的结构分配堆栈。
    3. 澄清:我的问题不是为什么结构或联合体的大小与其部分的大小相比更大。我理解原因是填充对齐。我的问题是编译器为union的不同实例分配了多个堆栈帧,即使它们是在不同的范围内定义的,而它不应该,并且对于具有相同字段的结构实际上不会这样做。

      谢谢!

2 个答案:

答案 0 :(得分:8)

显然至少有人试图放松gcc关于工会的严格走样偏执狂。

您可能希望确保编译的gcc源应用了此等效修补程序: http://codereview.appspot.com/4444051/

答案 1 :(得分:0)

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

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

总计 - 8个字节。

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

总计 - 16个字节。

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