考虑以下代码:
#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
但是,使用定义为 union 的 TRY 编译(意味着 testme 是一个 union),编译器为 main 分配的堆栈大小为 32 个字节:
$ gcc -DTRY=union -g -O2 test.c -o test
$ objdump -d ./test | ./checkstack.pl i386 | grep main
此外,在附加作用域中定义的结构/联合的任何附加实例在使用联合时会产生更大的堆栈分配,但在用作结构时不会扩大堆栈分配。
现在,这没有意义 - 联合应该占用更少的堆栈空间,如果有的话,而不是更多,然后是具有相同字段的结构!
即使在不同的范围内,GCC 似乎也将联合视为同时使用,但对结构却不这样做。
更多说明:
volatile 用于阻止编译器优化分配。释放 volatile 并在没有优化的情况下进行编译会产生相同的结果。
即使 testme 是一个具有联合作为成员之一的结构,也会观察到相同的行为。换句话说 - 一个结构的成员之一是 GCC 的一个联合就足够了,可以进行单独的堆栈分配。
编译器是 gcc 版本 4.4.3 (Ubuntu 4.4.3-4ubuntu5),但其他体系结构的其他 GCC 版本表现出相同的行为。
checkstack.pl 只是在 objdump 输出中搜索用于分配堆栈的指令(堆栈指针的子目录)。
我的问题:
- 为什么 GCC 会这样做?这是一个错误还是有这种行为的原因?
- 假设这不是一个错误,有没有办法解决这个问题并强制 GCC 为与联合相同的结构分配堆栈。
澄清:我的问题不是为什么结构或联合的大小看起来比它的部分更大。我知道原因是填充对齐。我的问题是编译器为联合的不同实例分配多个堆栈帧,即使它们是在不同的范围内定义的,而对于具有相同字段的结构,它不应该而且确实不这样做。
谢谢!