Размер структуры с символом, двойным, int и a 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, который содержит эти типы данных, он дает мне 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;
}

:РЕДАКТИРОВАТЬ

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

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

9 ответов

Решение

Есть несколько неиспользуемых байтов между некоторыми членами, чтобы сохранить правильное выравнивание. Например, указатель по умолчанию находится на 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                             |
+-------------------------------+

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

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

Из Википедии, выравнивание структуры данных:

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

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

  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 байт.

Это 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 на некоторых других)

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

Смотрите также это для получения дополнительной информации.

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

См. Список часто задаваемых вопросов comp.lang.c · Вопрос 2.12:

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

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

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

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

Ваш компилятор, вероятно, выравнивает int и указатели с кратными для 4 байтов и двойными с кратными для 8 байтов.

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

Другие вопросы по тегам