2014-12-18 2 views
3

Ну, после прочтения этого Size of structure with a char, a double, an int and a t я до сих пор не получить размер моей структуры, которая:Sizeof структуре в C

struct s { 
    char c1[3]; 
    long long k; 
    char c2; 
    char *pt; 
    char c3; 
} 

И sizeof(struct s) возвращает мне 40

Но согласно сообщению I говорил, я думал, что память должна нравится этот путь:

0 1 2 3 4 5 6 7 8 9 a b c d e f 
+-------------+- -+---------------------------+- - - - - - - -+ 
| c1   | |k       |    | 
+-------------+- -+---------------------------+- - - - - - - -+ 
10 11 12 13 14 15 16 17 
+---+- -+- -+- - - - - -+----+ 
|c2 | |pt |   | c3 | 
+---+- -+- -+- - - - - -+----+ 

И я должен получить 18 вместо 40 ... Может кто-нибудь объяснить мне, что я делаю неправильно? Большое спасибо !

+2

char не 1 байт .. но это 4 байта. 4x4 = 16 + 8 + 4 + 8 + 4 – SSpoke

+0

Я ожидаю, что долгое время будет выровнено на границе 8 байтов. Я ожидаю, что указатель будет выровнен по 4-байтовой границе. Получает половину от 18 до 40 – pm100

+1

Вы дали свои 'k' 8 байтов, но вы выровняли его на границе 4 байта. Зачем? Кроме того, почему 'pt' вдруг только 1 байт? Это указатель. – AnT

ответ

6

Предполагая, что требования к размеру указателя и выравнивания 8-байтовый на long long и указателей, а затем:

  • 3 байта для c1
  • 5 байт обивка
  • 8 байт для k
  • 1 байт   для c2
  • 7 байт заполнение
  • 8 байт для pt
  • 1 байт   для c3
  • 7 байт отступы

Это добавляет до 40 байт.

Задний пробел распределяется так, чтобы массивы структуры сохраняли все элементы структуры правильно выровненными.

Обратите внимание, что размеры, требования к выравниванию и, следовательно, отступы зависят от аппаратного оборудования, компилятора и ABI прикладного двоичного интерфейса. Правила, которые я использовал, являются общими правилами: N-байтовый тип (для N в {1, 2, 4, 8, 16}) должен быть выделен на границе N-байта. Массивы (как внутри структуры, так и массивы структуры) также должны быть правильно выровнены. Вы можете иногда динк с дополнением с помощью директив #pragma; будь осторожен. Как правило, лучше всего выложить структуру с наиболее строго выровненными объектами в начале и менее строго выровненными в конце.

Если вы использовали:

struct s2 { 
    long long k; 
    char *pt; 
    char c1[3]; 
    char c2; 
    char c3; 
}; 

размер требуется будет всего 24 байт, только с 3 байта задней отступы. Заказ имеет значение!

+0

ах да - 8 байт указателей. Почему заканчивается прокладка? Эффективность - так что следующая вещь выровнена на следующей главной границе? – pm100

+0

Задний отступ выделяется так, чтобы массивы структуры сохраняли все элементы структуры правильно выровненными. –

2

Размер структуры зависит от того, какой компилятор используется и какие параметры компилятора включены. Стандарт языка C не дает никаких обещаний о том, как память используется, когда компилятор создает структуры, а разные архитектуры (например, 32-разрядные WinTel и 64-разрядные WinTel) вызывают разные решения макета, даже когда используется один и тот же компилятор.

По существу, размер структуры равен сумме размеров байтов, необходимых элементам поля (которые обычно могут быть вычислены) плюс сумма байтов заполнения, введенных компилятором (который обычно не является известен).

0

Это из-за выравнивания, GCC имеет

#pragma pack(push,n) 
// declare your struct here 
#pragma pack(pop) 

, чтобы изменить его. Read here, а также __attribute__((__packed__)).

Если вы объявляете-структуру

struct packed 
{ 
    char c1[3]; 
    long long k; 
    char c2; 
    char *pt; 
    char c3; 
} __attribute__((__packed__)); 

затем компиляцией с gcc, sizeof(packed) = 18 так

c1: 3 
    k : 8 
    c2: 1 
    pt: 4 // it depends 
    c3: 1 

Видимо Visual C++ компилятор поддерживает #pragma pack(push,n) тоже.

Смежные вопросы