Выравнивание структуры с битовыми полями

Почему 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;
};

Поскольку битовые поля int находятся в одной единице хранения (и его размер, вероятно, sizeof(int), то есть 4), битовое поле uint16_t находится в другой (и его размер, вероятно, равен 2), а битовое поле float находится в другой (его размер, вероятно, равен 2). 4), и между y_1 и y_2, вероятно, имеется 2 байта заполнения для выравнивания. Используйте один и тот же тип для всех членов битового поля.

Jonathan Leffler 28.03.2024 20:00

Попробуйте изменить типы полей x_n на uint16_t.

dbush 28.03.2024 20:00

хорошо я понял. Что мне делать с битовым полем uint16_t, если у меня вместо int есть перечисления?

Vovyaklya 28.03.2024 20:05

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

Pete Becker 28.03.2024 20:10

Проверьте, есть ли в вашем компиляторе мета #pragma pack 1 или attibute для упаковки данных без выравнивания (пакет 1). Убедитесь также, что он разрешает нужные вам типы полей (до C23 разрешено меньше типов).

Frankie_C 28.03.2024 20:14

Использование побитовых операций с unsigned int более переносимо и стандартно, чем использование битовых полей.

Thomas Matthews 28.03.2024 20:17
sizeof(A) недействителен. Тег C удален.
chux - Reinstate Monica 28.03.2024 20:19

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

tadman 28.03.2024 20:21

@Frankie_C C++ имеет стандартные alignas начиная с C++11.

Remy Lebeau 29.03.2024 01:51

@RemyLebeau Опс. Я отвечал за язык C, а не за C++... Я ошибаюсь.

Frankie_C 30.03.2024 21:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
108
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Битовые поля не имеют хранилища, но имеют место в памяти того же размера, что и указанный вами скалярный тип, поэтому выравнивание обычно имеет как минимум тот же размер, но порядок в структуре не определяется до тех пор, пока не встретится поле нулевого размера. - "ненулевая последовательность битовых полей одного типа".

В вашем случае в системе с прямым порядком байтов ваша структура, скорее всего, либо упорядочена, как

<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. Я написал «вероятно», потому что реализация компилятора должна решить, как упаковать биты, но это более или менее распространенный способ сделать это. Обычно это одинаково для компиляторов на одной платформе в целях совместимости, но существуют исключения.

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