Подтвердить что ты не робот

Размер структуры с 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 байт. Это хорошо, или я потерял некоторые важные байты?

4b9b3361

Ответ 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), смещения, при которых элементы структуры будут выровнены, не указаны, за исключением того, что члены, объявленные позже, имеют более высокие адреса.