Почему GCC выделяет отдельное пространство стека для локальных объединений в разных областях? - PullRequest
7 голосов
/ 22 февраля 2012

Рассмотрим следующий код:

#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 рассматривает союзы как используемые одновременно, даже когда они находятся в разных областях, но не делает то же самое для структур.

Еще несколько уточнений:

  1. volatile используется, чтобы остановить компилятор от оптимизации назначений. Потеря volatile и компиляция без оптимизации дает одинаковые результаты.

  2. Даже если testme является структурой, в которой один из членов имеет объединение, наблюдается то же поведение. Другими словами - достаточно, чтобы один из членов структуры был объединением для GCC для отдельных выделений стека.

  3. Компилятор - версия gcc 4.4.3 (Ubuntu 4.4.3-4ubuntu5), но другие версии GCC для других архитектур показали то же поведение.

  4. checkstack.pl просто ищет в выходных данных objdump инструкции, используемые для выделения стека (под указателем стека).

Мой вопрос:

  1. Почему GCC делает это? это ошибка или есть причина для такого поведения?
  2. Предполагая, что это не ошибка, есть способ обойти это и заставить GCC выделить стек для элементов, таких же, как союзы.

Уточнение : Мой вопрос не в том, почему структура или объединение кажутся больше по размеру от размера его части. Я понимаю, что причина кроется в выравнивании. Моя проблема заключается в том, что компилятор выделяет несколько фреймов стека для разных экземпляров объединения, даже если они определены в разных областях, в то время как он не должен и не делает того же самого для структуры с одинаковыми полями.

Спасибо!

Ответы [ 2 ]

8 голосов
/ 22 февраля 2012

Очевидно, по крайней мере, была предпринята попытка ослабить строгую паранойю gcc в отношении профсоюзов.

Возможно, вы захотите убедиться, что исходный код gcc, из которого вы компилируете, имеет этот или эквивалентный патч: http://codereview.appspot.com/4444051/

0 голосов
/ 22 февраля 2012

Похоже на то, что имеет значение дополнение и базовое определение размера по умолчанию для Int.

В 32-битной карте памяти будет: Один (2 байта), Два (2 байта), Три (1 байт) (1байт) заполнение четырьмя (2 байтами)

Всего - 8 байтов.

в 64-битном формате: один (4 байта) два (4 байта) три (1 байт) (3 байта)padding) Четыре (4 байта)

Всего - 16 байтов.

Если вы измените «int» на «short int», память будет выглядеть по-другому.

...