如何知道为 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 是对的——唯一需要联合的时候是一个或多个成员具有不同的类型。也拼写:lumpsumPaymonthlyPayannualPay 【参考方案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;

让我们通过一个简单的例子来了解标签字段的使用。假设我们想要一个可以存储intdouble 类型数据的数组。这将通过使用union 成为可能。因此,首先定义一个联合类型,它将存储intdouble

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 将设置为INTDOUBLE”中的“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 你真的需要联合吗?带有两个ints 的结构就足够了。【参考方案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 获取/设置变量值? [复制]

如何在 gitlab-ci.yml 文件中通过 ssh 设置变量值

在从单选组中选择单选按钮时设置变量值

如何在Visual Studio中检查函数末尾的变量值

如何在编译时从表达式设置变量值?

关于jmeter中跨线程组?变量值传递的方法