Размер структуры с char, двойной, int и t
Когда я запускаю только фрагмент кода
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 байт. Это хорошо, или я потерял некоторые важные байты?
Ответы
Ответ 1
Есть несколько неиспользуемых байтов между некоторыми членами для сохранить правильность выравниваний. Например, указатель по умолчанию находится на 4-байтных границах для эффективности, т.е. Его адрес должен быть кратным 4. Если структура содержит только char и указатель
struct {
char a;
void* b;
};
то b
не может использовать сумматоры # 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 |
+-------------------------------+
Ответ 2
... это дает мне 24, и я смущен. Каковы дополнительные 7 байтов?
Это байты заполнения, вставленные компилятором. Заполнение структуры данных зависит от реализации.
Из Википедии Выравнивание структуры данных:
Согласование данных означает перенос данных со смещением памяти, равным нескольким кратным размеру слова, что увеличивает производительность системы из-за того, как процессор обрабатывает память. Для align данных может потребоваться вставить некоторые бессмысленные байты между концом последних данных структуру и начало следующего, что является дополнением к структуре данных.
Ответ 3
Чтобы немного расширить 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 байтов.
Ответ 4
Это 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 на некоторых других)
Ответ 5
Компилятору разрешено выравнивать элементы структуры по адресам для более быстрого доступа. например 32-битовые границы. Стандарту требуется только, чтобы члены объекта сохранялись в том порядке, в котором они объявлены. Поэтому всегда используйте sizeof
и offsetof
, когда вам нужна точная позиция в памяти.
Ответ 6
См. список вопросов comp.lang.c · Вопрос 2.12:
Почему мой компилятор оставляет дыры в структурах, тратит пространство и предотвращает "двоичный" ввод/вывод во внешние файлы данных? Могу ли я отключить это или иным образом управлять выравниванием полей структуры?
Ответ 7
Дополнительный размер исходит от выравнивания данных, т.е. члены выравниваются до кратных 4 или 8 байтов.
Ваш компилятор, вероятно, выравнивает int и указатели, чтобы умножить на 4 байта, а double - на 8 байтов.
Если вы переместите double в другую позицию внутри структуры, вы можете уменьшить размер структуры с 24 до 20 байтов. Но это зависит от компилятора.
Ответ 8
Также вам понадобится структура, чтобы выполнить заказ, который вам нужен. В этом случае, если вы используете gcc, вы должны использовать оператор __attribute__((packed))
.
См. также для получения дополнительной информации.
Ответ 9
$9.2/12 states - "Нестационарные члены данных (неединичного) класса, объявленные без промежуточного спецификатора доступа, распределяются так, что более поздние члены имеют более высокие адреса в объекте класса. Порядок распределения нестатических элементов данных разделен спецификатором доступа не указывается (11.1). Требования к выравниванию реализации
может привести к тому, что два соседних элемента не будут распределены сразу друг за другом; так что
требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).
Так же, как sizeof (double) и sizeof (int), смещения, при которых элементы структуры будут выровнены, не указаны, за исключением того, что члены, объявленные позже, имеют более высокие адреса.