Заполнение структуры данных

#c #data-structures

#c #структуры данных

Вопрос:

Что такое заполнение структуры данных в c и как мне проверить количество байтов, заполненных байтами?

 class a { public: int x; int y; int z; };
  

Комментарии:

1. Я прочитал, что оператор sizeof возвращает размер вместе с заполненными байтами, поэтому мне просто интересно.

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

Ответ №1:

Процессорам требуется, чтобы определенные типы данных имели определенные выравнивания. Например, процессору может потребоваться, чтобы значение int находилось на границе в 4 байта. Так, например, int может начинаться с ячейки памяти 0x4000 , но не может начинаться с 0x4001 . Итак, если вы определили класс:

 class a
{
public:
    char c;
    int i;
};
  

компилятору пришлось бы вставить заполнение между c и i , чтобы i можно было начинать с границы в 4 байта.

Комментарии:

1. это означает, что в вашем примере не было бы никакого заполнения, если бы оно начиналось с границы байта. каким оно должно быть.

2. Этот ответ, как правило, верен для подавляющего большинства процессоров / компиляторов, с которыми вы, вероятно, столкнетесь. Просто не полагайтесь на то, что это всегда точно верно.

3. «процессоры требуют» — иногда верно, в других случаях это не требуется (т. Е. Это не будет SIGBUS или аналогично, если не выровнено), но работает лучше.

4. Не совсем корректно. Большинство процессоров имеют байтовый адрес, поэтому целые числа могут начинаться с любого байтового адреса. Однако компиляторы будут размещать значение int на границе 4/8 байта, поскольку это повышает производительность системы из-за того, как центральный процессор обрабатывает операции с памятью.

Ответ №2:

 struct A
{
    char c;
    int i;
};

int main(int argc, char *argv[])
{
    A a;

    cout << "sizeof struct = " << sizeof(A) << endl;

    cout << "sizeof items  = " << sizeof(a.c)   sizeof(a.i) << endl;

    return 0;
}
  

Ответ №3:

заполнение выполняется по соображениям производительности — смотрите эту статью Выравнивание структуры данных для получения дополнительной информации.

Чтобы проверить, дополняет ли компилятор вашу структуру данных, вы могли бы написать простую программу:

 #include <iostream>

class a {
public:
    int x;
    int y;
    int z;
};

int main()
{
    std::cout << sizeof(a) << std::endl; // print the total size in bytes required per class instance

    a anInstance;
    std::cout << amp;anInstance.x << std::endl; // print the address of the x member
    std::cout << amp;anInstance.y << std::endl; // as above but for y
    std::cout << amp;anInstance.z << std::endl; // etc
}
  

Я добавил публичное объявление, чтобы избежать ошибок компилятора — это не повлияет на размер или заполнение.

Редактировать: Запуск этого на моем macbook air выдает следующий результат: 12 0x7fff5fbff650 0x7fff5fbff654 0x7fff5fbff658

Это показывает, что на моей машине общий размер составляет 12 байт, а каждый элемент находится на расстоянии 4 байт друг от друга. Целые числа равны 4 байтам каждый (что может быть подтверждено с помощью sizeof(int)). Заполнение отсутствует.

Попробуйте это с разными членами вашего класса, например:

 class b {
    public:
        char      w;
        char      x[6];
        int       y;
        long long z;
};
  

Комментарии:

1. «заполнение выполняется по соображениям производительности» … иногда, в других случаях, процессор фактически использует SIGBUS или аналогичный, если его просят получить доступ к не выровненным данным.

Ответ №4:

Lol просто создайте 2 идентичные структуры, сделайте одну из них упакованной, например

 struct foo {
  int  a;
  char b;
  int  c;
} 

struct bar {
  int  a;
  char b;
  int  c;
} __attribute__((__packed__));
  

sizeof(foo) - sizeof(bar)
даст вам объем заполнения. Или вы могли бы также вычислить вручную, как предложил Дак.