Почему sizeof(A) 12?
Должно быть: float(4) + x_0-pad(2) + y_1(2) = 8
Если все соответствует float, как этого избежать?
struct A
{
int x_0 : 1;
int x_1 : 1;
int x_2 : 1;
int x_3 : 2;
int x_4 : 2;
int x_5 : 2;
int x_6 : 3;
uint16_t pad : 4;
uint16_t y_1;
float y_2;
};
Попробуйте изменить типы полей x_n на uint16_t.
хорошо я понял. Что мне делать с битовым полем uint16_t, если у меня вместо int есть перечисления?
Расположение битовых полей зависит от компилятора. Вы можете либо найти документацию о том, что делает ваш компилятор, либо попробовать случайные вещи и надеяться получить то, что вы хотите. В частности, не требуется, чтобы эти переменные x_ были упакованы вместе и занимали ровно 12 бит.
Проверьте, есть ли в вашем компиляторе мета #pragma pack 1 или attibute для упаковки данных без выравнивания (пакет 1). Убедитесь также, что он разрешает нужные вам типы полей (до C23 разрешено меньше типов).
Использование побитовых операций с unsigned int более переносимо и стандартно, чем использование битовых полей.
sizeof(A) недействителен. Тег C удален.
Битовые поля являются источником многих страданий и путаницы. Избегайте, если можете.
@Frankie_C C++ имеет стандартные alignas начиная с C++11.
@RemyLebeau Опс. Я отвечал за язык C, а не за C++... Я ошибаюсь.





Битовые поля не имеют хранилища, но имеют место в памяти того же размера, что и указанный вами скалярный тип, поэтому выравнивание обычно имеет как минимум тот же размер, но порядок в структуре не определяется до тех пор, пока не встретится поле нулевого размера. - "ненулевая последовательность битовых полей одного типа".
В вашем случае в системе с прямым порядком байтов ваша структура, скорее всего, либо упорядочена, как
<32bit location #0> x_6 x_5 x_4 x_3 x_2 x_1 x_0 ...
<16bit location #1> pad ...
uint16_t y_1;
float y_2;
или он может разделять байты (чтобы не разбивать поля по границам байтов)
<8bit location #0> x_4 x_3 x_2 x_1 x_0 ...
<8bit location #1> x_6 x_5 ...
<an optional 16bit padding>
<16bit location #2> pad ...
uint16_t y_1;
float y_2;
Большинство современных компиляторов используют первый метод, и гарантируется, что ненулевые поля заполняют как можно большую часть связанного местоположения. Вот почему вы получили размер 12 байт: int (4) + 2 uint16_t(2) + float(4).
Примечание: вы также можете встретить компилятор, где int — это 16 бит, и тогда он будет работать так, как вы ожидали.
В системах с прямым порядком байтов или некоторых гибких архитектурах это может быть
<32bit location #0> ... x_0 x_1 x_2 x_3 x_4 x_5 x_6
<16bit location #1> ... pad
uint16_t y_1;
float y_2;
Другой тип приводит к рассмотрению нового местоположения. Вы можете добавить поле нулевого размера:
int x_break: 0;
где угодно, чтобы разбить последовательность и обеспечить частичный порядок. Неиспользуемые биты, отмеченные ..., формально не считаются заполнением, но работают аналогично.
Если пользователь не изменил требования к выравниванию struct, до/после <location #2> pad могут быть дополнения для удовлетворения требований к выравниванию int.
Примечание. Вы даже не можете гарантировать, что битовые поля начинаются с начала структуры, а только то, что общий порядок относительно других членов структуры сохраняется.
Примечание 2. Я написал «вероятно», потому что реализация компилятора должна решить, как упаковать биты, но это более или менее распространенный способ сделать это. Обычно это одинаково для компиляторов на одной платформе в целях совместимости, но существуют исключения.
Поскольку битовые поля
intнаходятся в одной единице хранения (и его размер, вероятно,sizeof(int), то есть 4), битовое полеuint16_tнаходится в другой (и его размер, вероятно, равен 2), а битовое полеfloatнаходится в другой (его размер, вероятно, равен 2). 4), и междуy_1иy_2, вероятно, имеется 2 байта заполнения для выравнивания. Используйте один и тот же тип для всех членов битового поля.