Синтаксис union в c++

Столкнулся с таким кодом, не смог найти, что означает такая запись в union и как с этим можно работать

обозначение класса:

class Other_Device{

public:
unsigned char Variable;
union SomeBufer {

unsigned char out[2];
struct {

unsigned char StructVariable;

} in;    //end of struct

};   //end of union

SomeBufer A_Buffer ;
SomeBufer T_Buffer ;

void classfunc(void);

};   //end of class

В самом cpp файле примерно следующие обращения к классу:

void Other_device::classfunc(void){
CppVariable = A_Buffer.in.StructVariable;
}

Variable = 0;

extern Other_device other_device;

other_device.A_Buffer.out[0] = 1;
other_device.T_Buffer.out[0] = 1;

Сами функции для меня интереса не представляют, хочется понимать, правильно ли я понимаю синтаксис класса.

Тот же код, но с комментариями, как я его понимаю

class Other_Device{

public:
unsigned char Variable;
union SomeBufer {

unsigned char out[2]             //создание массива не имеющего отношения к структуре, но относящегося к объединению
struct {                         //создание структуры внутри объединения

unsigned char StructVariable;

} in;    //end of struct         //in нужен для дальнейшего обращения к переменным структуры, а не к массиву out.

};   //end of union

SomeBufer A_Buffer ;             //Вот это не очень понимаю, создание двух массивов содержащих в себе массив out из объединения SomeBufer
SomeBufer T_Buffer ;

void classfunc(void);

};   //end of class

cpp файл

void Other_device::classfunc(void){
CppVariable = A_Buffer.in.StructVariable;
}

Variable = 0;

extern Other_device other_device;         //то, что необходимо для того, чтобы я мог обращаться к переменным класса Other_device, при этом добавляя в начале other_device. ?

other_device.A_Buffer.out[0] = 1;
other_device.T_Buffer.out[0] = 1;
// и можно ли обращаться к массиву объединения как other_device.SomeBuf.out напрямую, если мне не нужны два массива A_Buffer и T_Buffer с одинаковой структурой и если можно, то как это сделать без ошибки "type name is not allowed"

Можете пожалуйста подсказать именно относительно моих комментариев: правильно ли я понял написанный код и если нет, то в чем не прав?


Ответы (1 шт):

Автор решения: Vladimir

Что происходит

class Other_Device { // Класс с именем Other_Device
public:
    unsigned char Variable; // Поле класса с именем Variable и типом unsigned char
    
    union SomeBufer { // Объединение с именем SomeBufer
        unsigned char out[2] // Поле объединения с именем out и типом массив unsigned char размерностью 2
        struct { // Структура без имени
            unsigned char StructVariable;
        } in; // Поле объединения с именем in и типом этой структуры без имени
    };

SomeBufer A_Buffer; // Переменная A_Buffer с типом SomeBufer
SomeBufer T_Buffer; // Переменная T_Buffer с типом SomeBufer

void classfunc(void); // Объявление метода класса с именем classfunc
};
void Other_device::classfunc(void) { // Определение метода класса с именем classfunc

    // Читаем из поля класса A_Buffer, в нем - из поля объединения in, в нём - из поля анонимной стурктуры StructVariable и записываем прочитанное значение в CppVariable, чем бы это ни было
    CppVariable = A_Buffer.in.StructVariable; 
}

Variable = 0; // Пытаемся инициализировать Variable значением 0

extern Other_device other_device; // Создаем объект класса Other_device с именем other_device

other_device.A_Buffer.out[0] = 1; // Пытаемся обратиться к объекту класса other_device, в нем к полю A_Buffer, в нем к полю out и записать единицу в массив по индексу 0
other_device.T_Buffer.out[0] = 1; // Пытаемся обратиться к объекту класса other_device, в нем к полю T_Buffer, в нем к полю out и записать единицу в массив по индексу 0

Перепишем хотя бы часть кода по-человечески:

struct SomeStruct {
    unsigned char StructVariable;
};

union SomeBuffer { 
    unsigned char out[2] 
    SomeStruct in;
};

Структура больше не анонимная, и теперь это можно нормально прочитать. Мы явно видим, что в объединении есть всего две переменных: out и in. Поскольку все данные в объединении хранятся в общей памяти, то работает это так: при обращении к in.StructVariable вы обращаетесь к out[0], при обращении к out[0] вы обращаетесь in.StructVariable. Т.е., записав данные в in.StructVariable можно прочитать их же, используя out[0], и наоборот.

Вообще, если подходить с точки зрения стандарта языка C++, то попытка прочитать поле объединения, которое не было перед этим записано, считается неопределенным поведением (другими словами, не гарантируется не только то, что оно сработает, но, в том числе, не гарантируется и то, как именно оно сработает/не сработает). Однако, многие компиляторы поддерживают чтение из неактивных полей. Поэтому этот код с высокой долей вероятности работает так, как описано выше. см.объявление объединений. Кроме того, есть ещё язык C, где подобное легально.

→ Ссылка