Синтаксис 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 шт):
Что происходит
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, где подобное легально.