如何知道为 union 设置了哪个变量值?
Posted
技术标签:
【中文标题】如何知道为 union 设置了哪个变量值?【英文标题】:How to know which variable value is set for union? 【发布时间】:2014-12-05 11:47:47 【问题描述】:我正在优化一个项目。它包含一个选项结构,用户可以在其中一次选择一个选项。除了选项之外,我们还使用一个标志变量来检查为该记录设置了哪个选项值。 为了提高内存效率,我想将结构转换为联合。但是我怎么知道联合中设置了哪个变量值。因为 union 没有限制获取变量的值,即使没有设置。
struct options
int basicPay;
int lumsumPay;
int mothlyPay;
int weeklyPay;
int dailyPay;
int anualPay;
int payType; // Flag variable to check which option is selected
;
union OptimizeOptions
int basicPay;
int lumsumPay;
int mothlyPay;
int weeklyPay;
int dailyPay;
int anualPay;
int payType; // Confuse at here
;
【问题讨论】:
@user3121023 是对的——唯一需要联合的时候是一个或多个成员具有不同的类型。也拼写:lumpsumPay
、monthlyPay
和 annualPay
。
【参考方案1】:
Union 遇到一个问题,即没有简单的方法可以知道最后一次更改了 Union 的哪个成员。为了跟踪此信息,您可以将union
嵌入到具有另一个成员(称为“标签字段”或“判别”)的结构中。标记字段的目的是提醒更改/更新了哪个成员。你可以试试这个:
typedef struct
int payType; // Tag field
union
int basicPay;
int lumsumPay;
int mothlyPay;
int weeklyPay;
int dailyPay;
int anualPay;
OptimizeOptions;
Options;
但是,在您的情况下,没有必要为 union 编写六个单独的成员,因为它们都是 int
类型。因此可以简化为
typedef struct
enumBASIC_PAY, LUMSUM_PAY, MONTHLU_PAY, WEEKLY_PAY, DAILY_PAY, ANNUAL_PAY payType;
int pay;
Options;
让我们通过一个简单的例子来了解标签字段的使用。假设我们想要一个可以存储int
和double
类型数据的数组。这将通过使用union
成为可能。因此,首先定义一个联合类型,它将存储int
或double
。
typedef union
int i;
double d;
Num;
接下来我们要创建一个数组,其元素为Num
类型
Num num_arr[100];
现在,假设我们要分配 num_arr
的元素 0
来存储 25
,而元素 1
存储 3.147
。这可以作为
num_arr[0].i = 25;
num_arr[1].d = 3.147;
现在假设我们必须编写一个函数来打印num_arr
元素。函数应该是这样的:
void print_num(Num n)
if(n contains integer)
printf("%d", n.i);
else
printf("%f", n.d);
等等! print_num
怎么会决定 n
是否包含整数或 double
?
这将通过使用标签字段来完成:
typedef struct
enumINT, DOUBLE kind; //Tag field
union
int i;
double d;
u;
Num;
因此,每次将值分配给u
的成员时,kind
必须1设置为@ 987654349@ 或DOUBLE
提醒我们实际存储的类型。例如:
n.u.i = 100;
n.kind = INT;
print_num
函数是这样的:
void print_num(Num n)
if(n.kind == INT)
printf("%d", n.i);
else
printf("%f", n.d);
1:程序员有责任在每次分配给union
成员时更新标记字段。正如@ j_random_hacker 在comment 中指出的那样,忘记这样做会导致错误。
【讨论】:
您忘记声明union OptimizeOptions
类型的字段 - 目前您只是声明联合类型本身,但没有该类型的字段。
@HenningMakholm;接得好 :)。现在它已修复。
我建议将“kind
将设置为INT
或DOUBLE
”中的“can”更改为“must”,以明确这是程序员必须自己做的事情;忘记这样做会导致错误。
@j_random_hacker;同意。更新了答案。
加入enum
成员可能会更好,例如enum INT, DOUBLE kind;
代替(隐含分别为零和一),因为这样您可以将可能的选择直接放入struct
模板中,因此不会像旁边的一些“松散”的类似对象的宏。【参考方案2】:
您是否在struct
中尝试过union
?让我们看看下面的等效示例:
union options
int basicPay;
int lumsumPay;
int mothlyPay;
int weeklyPay;
int dailyPay;
int anualPay;
;
struct record
union options op; // Options union
int payType; // Flag variable to check which option is selected
联合 (options
) 将为其最大变量保留内存,您可以设置它的值,您的结构(记录)将跟踪该联合内存块,并且可以设置 payType
标志值,这将告诉你的程序来获取联合的特定变量。
【讨论】:
union options *op
不需要是一个指针,如果它是union options op
,那么struct record
的使用会更容易。
如果所有联合选项都属于同一类型int
你真的需要联合吗?带有两个int
s 的结构就足够了。【参考方案3】:
现在有 std::variant
封装了这个通用功能。
std::variant<int, float> x;
x = 42;
bool is_x_an_int = std::holds_alternative<int>(x); // YES
bool is_x_a_float = std::holds_alternative<float>(x); // NO
int value_of_x = std::get<int>(x); // 42
int an_error = std::get<float>(x); // exception
见https://en.cppreference.com/w/cpp/utility/variant。
【讨论】:
以上是关于如何知道为 union 设置了哪个变量值?的主要内容,如果未能解决你的问题,请参考以下文章
如何只允许 getter/setter 获取/设置变量值? [复制]