Недавно я работаю над окнами, и я обнаружил, что множество структур данных определяется как struct
с union
как переменные-члены. Пример этого будет EVT_VARIANT
в Windows.
Я не понял, в чем заключается цель этого.
Недавно я работаю над окнами, и я обнаружил, что множество структур данных определяется как struct
с union
как переменные-члены. Пример этого будет EVT_VARIANT
в Windows.
Я не понял, в чем заключается цель этого.
Когда a struct
содержит членов union
, это обычно делается как механизм экономии пространства. Если struct
может иметь определенные подтипы, по которым действительны только определенные члены, то union
- хороший способ не тратить пространство.
Например
enum NumberKind {
Integer,
FloatingPoint
};
struct Number {
NumberKind kind;
union {
int integerValue;
float floatValue;
};
};
В этом сценарии я определил номер struct
, который может иметь типы типов числовых значений: с плавающей запятой и integer. Недействительно иметь оба одновременно, а не тратить пространство, поскольку оба члена всегда определены. Я создал union
, что делает хранение обоих равным размеру самого большого.
Пример использования выше по запросу
void PrintNumber(Number value) {
if (value.kind == Integer) {
printf("%d\n", value.integerValue);
} else {
printf("%f\n", value.floatValue);
}
}
Представьте, что у вас есть структура, содержащая пакет данных. Данные в пакете могут быть нескольких разных типов, поэтому вы сохраняете тип в члене типа. Итак, чтобы прочитать данные в этом пакете, сначала проверьте тип, затем вы прочтете соответствующий элемент данных, который должен содержать данные в пакете.
Без объединений структура данных будет выглядеть так:
struct data {
type_t type;
int number;
char * string;
double fraction;
long long big_number;
}
Это будет довольно большая структура данных. Он использует достаточно места для хранения одного из возможных типов данных. Это немного лишнее, когда у вас обязательно будет только один из тех членов, содержащих полезную информацию в любой момент времени.
Если мы используем объединения:
struct data {
type_t type;
union payload {
int number;
char * string;
double fraction;
long long big_number;
}
}
Затем структура содержит только достаточно места для хранения типа плюс один из членов полезной нагрузки (т.е. вы выделили бы объем памяти, равный размеру type_t плюс размер наибольшего возможного члена полезной нагрузки). Это экономит нагрузку на пространство и намного эффективнее.
Однако вам нужно быть осторожным, потому что если полезная нагрузка содержит int, вы все равно можете считать ее двойной. Вероятно, вы просто получите чрезвычайно странные цифры, поскольку ваша программа пытается неправильно интерпретировать данные.
В качестве реликвии тех дней, когда 64 КБ было довольно много памяти, у вас есть средство на С++, которое позволяет нескольким переменным совместно использовать одну и ту же память (но, очевидно, не в то же время). Это называется объединением, и есть четыре основных способа их использования:
Вы можете использовать его так, чтобы переменная A занимала блок памяти в одной точке программы, которая позже занята другой переменной B другого типа, поскольку A больше не требуется. Я рекомендую вам не делать этого. Это не стоит риска ошибки, которая подразумевается в такой договоренности. Вы можете добиться такого же эффекта, динамически распределяя память.
Кроме того, у вас может быть ситуация в программе, где требуется большой массив данных, но вы не знаете заранее, каков будет тип данных - он будет определяться вводом данные. Я также рекомендую вам не использовать союзы в этом случае, так как вы можете добиться того же результата, используя пару указателей разных типов и, опять же, динамически распределяя память.
Третье возможное использование для объединения - это то, что вам может понадобиться время от времени - когда вы хотите интерпретировать одни и те же данные двумя или несколькими разными способами. Это может произойти, если у вас есть переменная типа long, и вы хотите рассматривать ее как два значения типа short. Windows иногда будет упаковывать два коротких значения в один параметр типа long, переданный функции. Другой экземпляр возникает, когда вы хотите обработать блок памяти, содержащий числовые данные, в виде строки байтов, просто чтобы переместить его.
Вы можете использовать объединение как средство передачи объекта или значения данных вокруг того, где вы не знаете заранее, каким будет его тип. Союз может обеспечить хранение любого из возможных диапазонов типов, которые у вас могут быть.
Если вы думаете, что я гений в объяснении того, что такое профсоюз, и некоторые из его возможных приложений, я не могу взять на это риск. (: Эта информация была получена от Ivor Horton Начиная Visual С++ 2010, который, как мне кажется, сидит здесь на моем столе. Надеюсь, это было полезно.
Объединение в методе структуры обычно используется, когда вам нужна структура в стиле варианта. Обычно он сопровождается идентификатором типа, который используется для определения того, какой элемент в объединении проверяется. Он также рассматривается обратным образом, например, в Xlib on * NIX, где он объединяется с структурами, причем первый член идентичен между всеми структурами, определяя, какая структура имеет нужные вам данные.
union означает, что у вас может быть один из его членов как возможное значение. В следующем примере вы видите значения для каждого из них. Но этот союз может быть членом какой-либо другой структуры, где достаточно указать только одно значение: float или integer, а не оба. Надеюсь, это поможет.
union {
float u_f;
int u_i;
}var;
var.u_f = 23.5;
printf("value is %f\n", var.u_f);
var.u_i = 5;
printf("value is %d\n", var.u_i)