arduino — массивы + объединения + структуры, содержащие битовые поля Переполнение стека

Я просто играл с битовыми полями и столкнулся с чем-то, что я не могу понять, как обойти.

(Обратите внимание на платформу: размер int = 2 байта, long = 4 байта, long long = 8 байтов — хотя стоит упомянуть, поскольку я знаю, что он может варьироваться. Также тип ‘byte’ определяется как ‘unsigned char’)

Я хотел бы иметь возможность сделать массив из двух 36-битных переменных и поместить их в объединение с массивом из 9 байтов. Вот что я придумал:

typedef union {
byte bytes[9];
struct {
unsigned long long data:36;
} integers[2];
} Colour;

Я работал над теорией, что компилятор поймет, что в составе анонимной структуры должно быть два битовых поля, и соберет их в пространство размером 9 байтов. Однако оказывается, что они выровнены на границе байтов, поэтому объединение занимает 10 байтов, а не 9, что имеет смысл.

Вопрос в том, есть ли способ создать массив из двух битовых полей, как этот? Я рассматривал атрибут «упакованный», но компилятор просто игнорирует его.

Хотя это работает как ожидалось (sizeof () возвращает 9):

typedef union {
byte bytes[9];
struct {
unsigned long long data0:36;
unsigned long long data1:36;
} integers;
} Colour;

Было бы предпочтительно иметь его доступным в виде массива.


Редактировать:
Спасибо cdhowie за объяснение, почему это не сработает.

К счастью, я подумал о том, как добиться того, чего я хочу:

typedef union {
byte bytes[9];
struct {
unsigned long long data0:36;
unsigned long long data1:36;
unsigned long long data(byte which){
return (which?data1:data0);
}
void data(byte which, unsigned long long _data){
if(which){
data1 = _data;
} else {
data0 = _data;
}
}
} integers;

} Colour;

3

Решение

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

Указатели должны быть выровнены по границам байтов, это именно так, как указатели. Поскольку в большинстве случаев массивы работают как указатели (за исключением), это просто невозможно, если битовые поля содержат количество битов, которые не делятся на 8 (что вы ожидаете) &(((Colour *) 0)->integers[1]) вернуть, если битовые поля были упакованы? Какое значение имело бы смысл?)

Во втором примере битовые поля могут быть плотно упакованы, потому что под капотом нет математики указателей. Чтобы объекты могли быть адресованы указателем, они должны находиться на границе байтов, поскольку байты — это единицы измерения, используемые для «измерения» указателей.

Вы заметите, что если вы попытаетесь взять адрес (((Colour *) 0)->integers.data0) или же data1 во втором примере компилятор выдаст ошибку именно по этой причине.

6

Другие решения

Других решений пока нет …