2010-08-15 2 views
18

Когда я запускаю только фрагмент кодаРазмер структуры с полукокса, двойной, в междунар и в

int *t; 
std::cout << sizeof(char) << std::endl; 
std::cout << sizeof(double) << std::endl; 
std::cout << sizeof(int) << std::endl; 
std::cout << sizeof(t)  << std::endl; 

это дает мне результат:

1 
8 
4 
4 

Всего: 17.

Но когда я проверяю sizeof struct, который содержит эти типы данных, он дает мне 24, и я смущен. Каковы дополнительные 7 байтов?

Это код

#include <iostream> 
#include <stdio.h> 
struct struct_type{ 
    int i; 
    char ch; 
    int *p; 
    double d; 
} s; 

int main(){ 
    int *t; 
    //std::cout << sizeof(char) <<std::endl; 
    //std::cout << sizeof(double) <<std::endl; 
    //std::cout << sizeof(int) <<std::endl; 
    //std::cout << sizeof(t)  <<std::endl; 

    printf("s_type is %d byes long",sizeof(struct struct_type)); 

    return 0; 
} 

: EDIT

Я обновил свой код, как этот

#include <iostream> 
#include <stdio.h> 
struct struct_type{ 
    double d_attribute; 
    int i__attribute__(int(packed)); 
    int * p__attribute_(int(packed));; 
    char ch; 
} s; 

int main(){ 
    int *t; 
    //std::cout<<sizeof(char)<<std::endl; 
    //std::cout<<sizeof(double)<<std::endl; 
    //std::cout<<sizeof(int)<<std::endl; 
    //std::cout<<sizeof(t)<<std::endl; 

    printf("s_type is %d bytes long",sizeof(s)); 

    return 0; 
} 

и теперь он показывает мне 16 байт. Это хорошо, или я потерял несколько важных байтов?

+0

Это C++, а не C. – habnabit

ответ

49

Существует несколько неиспользуемых байтов между некоторыми членами до keep the alignments correct. Например, указатель по умолчанию находится на границах 4 байта для эффективности, то есть его адрес должен быть кратен 4. Если структура содержит только символ и указатель

struct { 
    char a; 
    void* b; 
}; 

затем b не может использовать adderss # 1 - он должен быть помещен на # 4.

0 1 2 3 4 5 6 7 
+---+- - - - - -+---------------+ 
| a | (unused) | b    | 
+---+- - - - - -+---------------+ 

В вашем случае, дополнительные 7 байт поступает от 3 байта из-за выравнивания int* и 4 байта за счет выравнивания double.

0 1 2 3 4 5 6 7 8 9 a b c d e f 
+---------------+---+- - - - - -+---------------+- - - - - - - -+ 
| i    |ch |   | p    |    | 
+---------------+---+- - - - - -+---------------+- - - - - - - -+ 
10 11 12 13 14 15 16 17 
+-------------------------------+ 
| d        | 
+-------------------------------+ 
+13

+1 для искусства ASCII. –

+1

+1 для диаграммного представления. –

+0

... XD. Просто потратил около 10 минут, набрав полное представление о своей структуре памяти; даже включил в себя предложение, чтобы украсть его, если вы думаете, что это даст вам дальнейший ответ, и я отправлю его, чтобы узнать, что вы уже добавили свой собственный. Ах хорошо. XD. – Stephen

9

... это дает мне 24, и я смущен. Каковы дополнительные 7 байтов?

Это байты заполнения, вставленные компилятором. Заполнение структуры данных зависит от реализации.

Материал из Википедии, Data structure alignment:

Выравнивание данных означает, что ввод данных в памяти коррекций равно некоторому кратному размеру слова, что повышает производительность системы благодаря тому, как процессор обрабатывает память. Для данных align данных может потребоваться вставить некоторые бессмысленные байты между окончанием последней структуры данных и началом следующего, что является дополнением к структуре данных.

+0

Да.Но когда я предполагаю, что выравнивание = 4, я ожидал бы 20, а не 24. –

+7

@Henk: 'double' на Windows x86 имеет выравнивание = 8. – kennytm

+0

@Kenny: когда все члены 8-выровнены, вы получаете 32. Когда только char padded to 4: 20. –

0

Компилятор позволяет выравнивать элементы структуры по адресам для более быстрого доступа. например 32-битовые границы. Стандарту требуется только, чтобы члены объекта сохранялись в том порядке, в котором они объявлены. Поэтому всегда убедитесь, что вы используете sizeof и offsetof, когда вам нужна точная позиция в памяти.

0

См comp.lang.c FAQ list · Question 2.12:

Почему мой компилятор оставляя дыры в структурах, тратить пространство и предотвращения `` двоичную '' I/O для внешних файлов данных? Могу ли я отключить это или иным образом управлять выравниванием полей структуры?

0

Дополнительный размер исходит от выравнивания данных, то есть элементы выравниваются, умножая на 4 или 8 байтов.

Ваш компилятор, вероятно, выравнивает int и указатели, чтобы умножить на 4 байта, а double - на 8 байтов.

Если вы переместите двойной объект в другое место внутри структуры, вы можете уменьшить размер структуры с 24 до 20 байтов. Но это зависит от компилятора.

0

Также вам нужна структура для заказа заказа. В этом случае, если вы используете gcc, вы должны использовать оператор __attribute__((packed)).

See also this для получения дополнительной информации.

+0

Есть ли способ в C (или gcc) указать, что конкретный элемент данных может быть неровным? Некоторые процессоры просто не поддерживают прямой доступ к неуравновешенным данным, поэтому 32-разрядное чтение или запись необходимо разделить на операции и сдвиги байтов. Код для этого был бы расточительным, если бы применялся к разыменованию каждого 32-разрядного указателя, но было бы полезно указать, что некоторые указатели должны быть разыменованы таким кодом. – supercat

+0

@supercat: почему бы вам просто не использовать memcpy? 'memcpy ((void *) & place, (const void *) & my_word, sizeof (my_word));' – Dacav

1

Это 24 байта из-за заполнения. Большинство компиляторов обрабатывают данные до кратного размера. Итак, 4-байтовый int дополняется кратным 4 байтам. 8-байтовый двойник дополняется кратным 8 байтам. Для вашей структуры, это означает:

struct struct_type{ 
    int i; // offset 0 (0*4) 
    char ch; // offset 4 (4*1) 
    char padding1[3]; 
    int *p; // offset 8 (2*4) 
    char padding1[4]; 
    double d; // offset 16 (2*8) 
}s; 

Вы можете оптимизировать как-структуру, что:

struct struct_type{ 
    double d; 
    int i; 
    int *p; 
    char ch; 
}s; 

SizeOf (s) == 17 на большинстве компиляторов (20 на некоторых других)

+0

Даже после переупорядочения sizeof все равно должно быть 24, потому что 'double' имеет 8-байтовое выравнивание (вместо 4). – kennytm

0

$ 9.2/12 states - «Нестационарные члены данных (неединичного) класса, объявленные без промежуточного спецификатора доступа, распределяются так, что более поздние члены имеют более высокие адреса в объекте класса. Порядок распределения нестатических элементов данных, разделенных доступом -специалист не указан (1 1.1). Требования к выравниванию реализации могут привести к тому, что два соседних элемента не будут распределены сразу после друг друга; так что может быть Требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1). "

Так же, как и sizeof (double) и sizeof (int), смещения, при которых элементы структуры будут выровнены, не указано, за исключением того, что участники, объявленные позже, находятся на более высоких адресах.

7

Чтобы немного расширить превосходный ответ KennyDM (Kenny - пожалуйста, украдите это, чтобы добавить свой ответ, если хотите), это, вероятно, выглядит как структура вашей памяти после того, как компилятор выровнял все переменные:

0 1 2 3 4 5 6 7 
+-------------------+----+-----------+ 
| i     | ch | (unused) | 
+-------------------+----+-----------+ 

    8 9 10 11 12 13 14 15 
+-------------------+----------------+ 
| p     | (unused)  | 
+-------------------+----------------+ 

16 17 18 19 20 21 22 23 
+------------------------------------+ 
| d         | 
+------------------------------------+ 

Итак, из-за 3-байтового зазора между «ch» и «p» и 4-байтового зазора между «p» и «d» вы получаете 7-байтное дополнение для вашей структуры, таким образом, размер 24 байта. Поскольку у вашей среды double есть 8-байтовое выравнивание (т. Е. Оно должно находиться в собственном блоке из 8-байтов, как вы можете видеть выше), то весь struct также будет выровнен по 8 байт по всему, и поэтому даже переупорядочить переменные не изменят размер от 24 байтов.

+0

Поскольку 'double' имеет 8-байтовое выравнивание (иначе структура была бы 20 байтов!), После' ch' будет добавлено 7-байтное дополнение даже после перегруппировки. – kennytm

+0

А, так что 'double' с 8-байтовым выравниванием приводит к тому, что целая' struct' делает это? Я этого не знал, спасибо! – Stephen

+1

Да, в общем, вся структура должна иметь такое же выравнивание, что и «наиболее выровненный» член. Представьте себе, что если у вас есть массив этих структур, каждый из них должен правильно выровнять свой 'double' член, что возможно только в том случае, если struct имеет такое же выравнивание, что и член' double'. – jalf

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