Почему short хранится как 4 байта в структуре в C? - PullRequest
2 голосов
/ 07 мая 2009

У меня есть две следующие структуры:

Проблема в том, что sizeof (Content) возвращает 160. Структура состоит из 11 шортов, 6 дюймов, 76 символов, 7 чисел с плавающей запятой, 1 двойного, что в сумме добавляет 158 байт. Я посчитал три раза, и разница все еще составляет 2 байта.

typedef struct TIME_T { 
    short year,mon,day; 
    short hour,min,sec; 
} TIME;

typedef struct { 
    int no; 
    char name[20]; 
    char Code[10]; 
    char DASType[10]; 
    short wlen; 
    float VLtd; 
    int samp; 
    int comp; 
    int locationID; 
    short TranMode; 
    char TranIns[12]; 
    short TimerMode; 
    char ClkType[12]; 
    float ClkErr; 
    float lat; 
    float lon; 
    float alt; 
    float azimuth,incident; 
    short weight; 
    short veloc; 
    int oritype; 
    char seismometer[12]; 
    double sens; 
    TIME start_time; 
    int record_samples; 
} Content;

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

int main(void)
{   
    Content content;
    printf("Sizeof Content: %d\n", sizeof(content));
    printf("Sizeof int content.no: %d\n", (int)&content.name - (int)&content.no);
    printf("Sizeof char[20] content.name: %d\n", (int)&content.Code - (int)&content.name);
    printf("Sizeof char[10] content.Code: %d\n", (int)&content.DASType - (int)&content.Code);
    printf("Sizeof char[10] content.DASType: %d\n", (int)&content.wlen - (int)&content.DASType);
    printf("Sizeof short content.wlen:  %d\n", (int)&content.VLtd - (int)&content.wlen);
    printf("Sizeof float content.VLtdL %d\n", (int)&content.samp - (int)&content.VLtd);
    printf("Sizeof int content.samp: %d\n", (int)&content.comp - (int)&content.samp);
    printf("Sizeof int content.comp: %d\n", (int)&content.locationID - (int)&content.comp);
    printf("Sizeof int content.locationID: %d\n", (int)&content.TranMode - (int)&content.locationID);
    printf("Sizeof short content.TranMode: %d\n", (int)&content.TranIns - (int)&content.TranMode);
    printf("Sizeof char[12] content.TranIns: %d\n", (int)&content.TimerMode - (int)&content.TranIns);
    printf("Sizeof short content.TimerMode: %d\n", (int)&content.ClkType - (int)&content.TimerMode);
    printf("Sizeof char[12] content.ClkType: %d\n", (int)&content.ClkErr - (int)&content.ClkType);
    printf("Sizeof float content.ClkErr: %d\n", (int)&content.lat - (int)&content.ClkErr);
    printf("Sizeof float content.lat: %d\n", (int)&content.lon - (int)&content.lat);
    printf("Sizeof floatcontent.lon: %d\n", (int)&content.alt - (int)&content.lon);
    printf("Sizeof floatcontent.alt: %d\n", (int)&content.azimuth - (int)&content.alt);
    printf("Sizeof floatcontent.azimuth: %d\n", (int)&content.incident - (int)&content.azimuth);
    printf("Sizeof floatcontent.incident: %d\n", (int)&content.weight - (int)&content.incident);
    printf("Sizeof short content.weight: %d\n", (int)&content.veloc - (int)&content.weight);
    printf("Sizeof short content.veloc: %d\n", (int)&content.oritype - (int)&content.veloc);
    printf("Sizeof int content.oritype: %d\n", (int)&content.seismometer - (int)&content.oritype);
    printf("Sizeof char[12] content.seismometer: %d\n", (int)&content.sens - (int)&content.seismometer);
    printf("Sizeof double content.sens: %d\n", (int)&content.start_time - (int)&content.sens);
    printf("Sizeof TIME content.start_time: %d\n", (int)&content.record_samples - (int)&content.start_time);
    printf("Sizeof int content.record_samples: %d\n", sizeof(content.record_samples));

    getchar();
    return 0;
}

Вывод выглядит следующим образом:

Sizeof int content.no: 4
Sizeof char[20] content.name: 20
Sizeof char[10] content.Code: 10
Sizeof char[10] content.DASType: 10
Sizeof short content.wlen:  4
**Sizeof float content.VLtdL 4**
Sizeof int content.samp: 4
Sizeof int content.comp: 4
Sizeof int content.locationID: 4
Sizeof short content.TranMode: 2
Sizeof char[12] content.TranIns: 12
Sizeof short content.TimerMode: 2
Sizeof char[12] content.ClkType: 12
Sizeof float content.ClkErr: 4
Sizeof float content.lat: 4
Sizeof floatcontent.lon: 4
Sizeof floatcontent.alt: 4
Sizeof floatcontent.azimuth: 4
Sizeof floatcontent.incident: 4
Sizeof short content.weight: 2
Sizeof short content.veloc: 2
Sizeof int content.oritype: 4
Sizeof char[12] content.seismometer: 12
Sizeof double content.sens: 8
Sizeof TIME content.start_time: 12
Sizeof int content.record_samples: 4

Компилятор MSVC8, UNICODE не определен, другой макрос не определен. Это x86.

Я попытался скомпилировать тот же код в gcc версии 3.4.4, вывод такой же. Sizeof short content.wlen: 4

Может кто-нибудь объяснить мне это?

Заранее спасибо.

РЕДАКТИРОВАТЬ: Спасибо за ответ! Я получил это сейчас.

Ответы [ 9 ]

23 голосов
/ 07 мая 2009

только короткий ответ: выравнивание

11 голосов
/ 07 мая 2009

Вы не можете определить размер структуры, просто добавив размеры всех ее компонентов - компилятору разрешено вставлять отступы между полями, и это часто делается.

4 голосов
/ 07 мая 2009

Выравнивание - в 32-битной архитектуре намного эффективнее передавать память в 32-битных блоках. На самом деле вы вообще не сэкономите память, сохранив короткое замыкание в 16 битах, поскольку оно все равно будет частью связанного 32-битного слова.

3 голосов
/ 07 мая 2009

Члены структуры часто выровнены по 4-байтовым границам, если компилятор считает, что доступ будет более удобным в этом случае. Подобное поведение происходит с char.

Вы можете попытаться оптимизировать объем памяти вашей структуры, сложив вместе шорты, чтобы два последовательных шорта использовали одно 32-битное слово. Не забудьте перепроверить результаты компилятора.

3 голосов
/ 07 мая 2009

Увеличивает ли добавление еще одного короткого замыкания в структуру или сохраняет его прежним? Я держу пари, что он остается того же размера.

Оба компилятора работают над выравниванием 8-байтной структуры (я полагаю), поэтому некоторые поля будут "расширены", чтобы занять дополнительное место; фактические операции с этим полем будут вести себя так, как если бы это был «правильный» размер.

3 голосов
/ 07 мая 2009

Вы рассчитываете не размер полей, а «расстояние» между ними, поэтому я думаю, что вы видите выравнивание слов в структуре.

2 голосов
/ 07 мая 2009

Как сказал dfa, это связано с выравниванием. Одна «хорошая практика», которая может помочь уменьшить размер ваших структур, - это упорядочить их элементы по их индивидуальному размеру (фактически их индивидуальному выравниванию, но размер часто достаточно хорош), начиная с самого большого элемента.

Это не всегда так, но большую часть времени.

2 голосов
/ 07 мая 2009

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

1 голос
/ 07 мая 2009

Взгляните на pahole, сокращение от Poke-a-Hole. Это один из инструментов DWARF2, используемый для поиска дырок в структурах, причем дыры являются пробелами между элементами из-за правил выравнивания, которые можно использовать для новых элементов структуры или реорганизовать для уменьшения размера.

Подробнее об этом можно прочитать в этой статье LWN , написанной автором программы Арнальдо Карвалью де Мело.

В сети не так много учебников, но эта вики-страница на CERN несколько полезна.

...