Структуры в С - PullRequest
       58

Структуры в С

0 голосов
/ 23 августа 2010

Я получил такую ​​структуру:

struct bar {
    char x;
    char *y;
};

Я могу предположить, что в 32-битной системе это заполнение для char сделает его общим 4 байта, а указатель в 32-битном равен 4, так что общий размер будет 8, верно?

Я знаю, что все это зависит от реализации, но я думаю, что если оно находится в пределах 1-4, оно должно быть дополнено до 4, в пределах от 5-8 до 8 и 9-16 в пределах 16, верно? это похоже на работу.

Могу ли я сказать, что структура будет 12 байтов в арке x64, потому что указатели будут 8 байтами? Или как ты думаешь, что должно быть?

Ответы [ 6 ]

4 голосов
/ 23 августа 2010

Я могу предположить, что в 32-битной системе что pad для char сделает его 4 Всего байт, и указатель в 32 бит 4, поэтому общий размер будет 8 право

Это небезопасно предполагать, но так будет часто, да. Для x86 поля обычно выровнены на 32 бита. Причина этого заключается в повышении производительности системы за счет использования памяти (см. здесь ).

Могу ли я сказать, что структура будет 12 байтов в арке x64, потому что указатели 8 байтов? Или что ты думаешь так должно быть?

Аналогично, для x64 поля обычно выровнены на 64-битные / 8-байтовые, поэтому sizeof(bar) будет равно 16.

Однако, как отмечает Андерс, все это улетает в окно, как только вы начинаете играть с выравниванием через / Zp , директиву pack или все, что поддерживает ваш компилятор.

1 голос
/ 23 августа 2010

$ 9,2 / 12-

Нестатические данные членов (не объединенный) класс, объявленный без промежуточный спецификатор доступа распределены так, чтобы более поздние члены имели более высокие адреса в классе объект. Порядок выделения нестатические члены данных, разделенные спецификатор доступа не указан (11.1). Выравнивание реализации требования могут вызвать два смежных Члены не должны быть распределены сразу после друг друга; так может требования к пространству для управления виртуальные функции (10.3) и виртуальные базовые классы (10.1).

Итак, это сильно зависит от реализации, как вы уже упоминали.

1 голос
/ 23 августа 2010

Вы не можете предполагать что-либо вообще.Каждая платформа определяет свои собственные правила заполнения.

Тем не менее, любая архитектура, использующая «естественное» выравнивание, где операнды дополняются до своего собственного размера (необходимого и достаточного, чтобы избежать расслоения естественно выровненных страниц, кэшированных строк и т. Д.), сделает bar в два раза больше размера указателя.

Таким образом, с учетом естественных правил выравнивания и ничего более, 8 байтов в 32-битной, 16 байтов в 64-битной.

1 голос
/ 23 августа 2010

Это переключатель компилятора, вы ничего не можете предположить.Если вы предполагаете, что у вас могут возникнуть проблемы.

Например, в Visual Studio вы можете использовать прагму pack (1) так, чтобы она находилась непосредственно на границе байта.

0 голосов
/ 24 августа 2010

Как уже упоминалось, нельзя полагаться на поведение между платформами. Однако, если вам все еще нужно это сделать, то вы можете использовать BOOST_STATIC_ASSERT(), чтобы убедиться, что если допущения нарушены, вы обнаружите это во время компиляции, например,

#include <boost/static_assert.hpp>
#if ARCH==x86                             // or whatever the platform specific #define is
  BOOST_STATIC_ASSERT(sizeof(bar)==8);
#elif ARCH==x64
  BOOST_STATIC_ASSERT(sizeof(bar)==16);
#else ...

Если имеется alignof(), вы также можете использовать это для проверки вашего предположения.

0 голосов
/ 23 августа 2010

Не совсем.

Заполнение зависит от требования выравнивания следующего элемента. Естественным выравниванием встроенных типов данных является их размер.

Заполнение перед элементами char отсутствует, поскольку их требование выравнивания равно 1 (при условии, что char равен 1 байту).

Например, если за символом (снова предположим, что это один байт) следует короткое замыкание, которое, скажем, составляет 2 байта, может быть до 1 байта заполнения, поскольку короткое замыкание должно быть выровнено по 2 байта. Если за символом следует двойное значение размера 8, может быть до 7 байтов заполнения, потому что двойное выравнивается по 8 байтов. С другой стороны, если после короткого замыкания следует двойное, может быть до 6 байтов заполнения.

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

struct baz {
    double d;
    char c;
};

элемент с наибольшим требованием выравнивания равен d, его требование выравнивания равно 8, что дает sizeof (baz) == 2 * alignof (double). После элемента c имеется 7 байтов заполнения хвоста.

gcc и другие современные компиляторы поддерживают оператор __alignof (). Существует также портативная версия в Boost.

...