Рассмотрим следующий код:
#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 является 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 выделить стек для элементов, таких же, как союзы.
Уточнение : Мой вопрос не в том, почему структура или объединение кажутся больше по размеру от размера его части. Я понимаю, что причина кроется в выравнивании. Моя проблема заключается в том, что компилятор выделяет несколько фреймов стека для разных экземпляров объединения, даже если они определены в разных областях, в то время как он не должен и не делает того же самого для структуры с одинаковыми полями.
Спасибо!