Как gcc рассчитывает необходимое пространство для структуры? - PullRequest
4 голосов
/ 06 августа 2011
struct {
   integer a;
   struct c b;
   ...
}

В общем, как gcc вычисляет необходимое пространство? Здесь есть кто-нибудь, кто когда-либо заглядывал во внутренние органы?

Ответы [ 4 ]

12 голосов
/ 06 августа 2011

Я не "заглянул во внутренности", но это довольно ясно, и любой здравомыслящий компилятор сделает это точно так же. Процесс идет как:

  1. Начните с размера 0.
  2. Для каждого элемента округлите размер до следующего кратного выравнивания для этого элемента, затем добавьте размер этого элемента.
  3. Наконец, округляем размер до наименьшего общего кратного выравнивания всех элементов.

Вот пример (предположим, int имеет 4 байта и имеет 4 байта выравнивания):

struct foo {
    char a;
    int b;
    char c;
};
  1. Размер изначально равен 0.
  2. Округление до выравнивания char (1); размер по-прежнему 0.
  3. Добавить размер char (1); размер сейчас 1.
  4. Округление до выравнивания int (4); размер сейчас 4.
  5. Добавить размер int (4); размер сейчас 8.
  6. Округление до выравнивания char (1); размер по-прежнему 8.
  7. Добавить размер char (1); размер сейчас 9.
  8. Округление до lcm (1,4) (4); размер сейчас 12.

Редактировать: Чтобы выяснить, почему последний шаг необходим, предположим, что вместо этого размер был просто 9, а не 12. Теперь объявите struct foo myfoo[2]; и рассмотрите &myfoo[1].b, что на 13 байт после начала myfoo и 9 байт после &myfoo[0].b. Это означает, что невозможно, чтобы myfoo[0].b и myfoo[1].b были выровнены с требуемым выравниванием (4).

1 голос
/ 06 августа 2011

Не существует действительно стандартизированного способа выравнивания структуры, но практическое правило выглядит так: вся структура выравнивается по границе 4 или 8 байтов (в зависимости от платформы). Внутри структуры каждый член выравнивается по размеру. Итак, следующие пакеты без подкладки:

char         // 1
char
char
char
short int    // 2
short int
int          // 4

Это будет иметь общий размер 12. Однако следующий следующий вызовет заполнение:

char   // 1, + 1 bytes padding
short  // 2
int    // 4
char   // 1, + 1 byte padding
short  // 2
char   // 1
char   // 1, + 2 bytes padding

Теперь структура занимает 16 байтов.

Это просто типичный пример, детали будут зависеть от вашей платформы. Иногда вы можете указать компилятору никогда не добавлять заполнение - это приведет к более дорогому доступу к памяти (возможно, к проблемам с параллелизмом), но сэкономит место.

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

0 голосов
/ 02 августа 2013

Изменили ваш код так, чтобы он компилировался и запускался на платформе компилятора Eclipse / Microsoft C:

    struct c {
       int a;
       struct c *b;
    };

    struct c d;

    printf("\nsizeof c=%d, sizeof a=%d, sizeof b=%d",
                sizeof(d), sizeof(d.a), sizeof(d.b));

    printf("\naddrof c  =%08x", &c);
    printf("\naddrof c.a=%08x", &c.a);
    printf("\naddrof c.b=%08x", &c.b);

Приведенный выше фрагмент кода дал следующий вывод:

   sizeof c=8, sizeof a=4, sizeof b=4
   addrof c  =0012ff38
   addrof c.a=0012ff38
   addrof c.b=0012ff3c

Doчто-то вроде этого, чтобы вы могли видеть (БЕЗ УГАДЫВАНИЯ), как именно ваш компилятор форматирует структуру.

0 голосов
/ 06 августа 2011

Размер структуры определяется реализацией, но трудно сказать, какой будет размер вашей структуры без дополнительной информации (она неполная).Например, учитывая это struct:

struct MyStruct {
     int abc;
     int def;
     char temp;
};

Дает размер 9 на моем компиляторе. 4 байтов для int и 1 байтов для char.

...