C 匿名工会的目的是什么?

C 匿名工会的目的是什么?,c,unions,c11,C,Unions,C11,通过在结构中声明匿名联合,您可以直接访问成员。这是有道理的,我认为,就像一个普通的工会一样,你只能从最近写入的值中读取 #包括 结构范围 { //匿名工会 联盟 { 炭α; int-num; }; }; int main() { 结构范围x; x、 num=65; //请注意,可以直接访问union的成员 printf(“x.alpha=%c,x.num=%d”,x.alpha,x.num); 返回0; } 那么,如果我可以一直访问所有变量,那又有什么意义呢?为什么不在“scope

通过在结构中声明匿名联合,您可以直接访问成员。这是有道理的,我认为,就像一个普通的工会一样,你只能从最近写入的值中读取

#包括
结构范围
{ 
//匿名工会
联盟
{ 
炭α;
int-num;
}; 
}; 
int main()
{ 
结构范围x;
x、 num=65;
//请注意,可以直接访问union的成员
printf(“x.alpha=%c,x.num=%d”,x.alpha,x.num);
返回0;
} 

那么,如果我可以一直访问所有变量,那又有什么意义呢?为什么不在“scope”的作用域中声明变量呢?

您可以对同一内存段进行不同的解释。它广泛应用于协议实现中。接收字节缓冲区,并根据不同的标志,根据需要对其进行处理/解码

在本例中,int和char的大小和字节顺序不同,根据所访问成员的值未指定。一般来说,它可能是一个陷阱表示,它会触发未定义的行为

(如果您将
char
更改为
unsigned char
,这将是安全的,因为
unsigned char
不能有陷阱表示。因此,您的程序将运行以完成并打印某些内容,但C标准没有指定为
x.alpha
打印什么值)

当然,任何给定的实现都可能指定实际获得的值(例如
x.num
)的低字节或高字节)。因此,这样的代码很可能只在这样的实现上工作,而不是为了便于移植或符合标准


正如Peter所指出的,所有这些都与使用匿名联合或老式联合无关。

关键是
struct Scope
可以有其他成员。一个更现实的例子:

struct Scope 
{ 
    union
    { 
        int num; 
        uint8_t num_byte [sizeof(int)];
    }; 
    int foo;
}; 
现在,您可以通过
obj.num
obj.num\u byte[i]
访问
struct Scope
成员。在内存中的联合之后,将有一个不同的变量
foo
,因此显然联合成员不能移出到结构中

如果不是匿名联合,我们必须键入类似于
obj.name.num
,其中name可能只是杂乱无章


关于阅读不同的联合成员,你的声明“你只能从最近写的值中读取”在C中是不正确的。注意C和C++在这里是不同的。p> C17 6.5.2.3规定:

后缀表达式,后跟。运算符和标识符指定的成员 联合体结构或联合体。该值是命名成员的值(95),如果 第一个表达式是左值

如果脚注95)有帮助:

95)如果用于读取联合对象内容的成员与上次用于读取的成员不同 将值存储在对象中时,将重新解释该值的对象表示形式的相应部分 作为6.2.6中所述新类型的对象表示(有时称为“类型”的过程 双关语')。这可能是一个陷阱表示

脚注中提到的6.2.6部分:

当值存储在union类型的对象的成员中时,该对象的字节数 与该成员不一致但与其他成员一致的陈述 取未指定的值

当运算符应用于具有多个对象表示形式的值时, 所使用的对象表示不应影响结果的值。哪里 值存储在使用具有多个对象表示形式的类型的对象中 该值未指定使用哪种表示法,但应使用陷阱表示法 无法生成


这在简单的英语中意味着C允许类型双关,但程序员有责任确保它在对齐/填充、陷阱表示、结尾等方面是可行的。

这并不是说允许或不允许访问“所有的变量”(用你的话来说)。无论联合是匿名的还是命名的,行为都是未定义的。在您的示例中,在(最近)分配了
x.num
(或反之亦然)之后访问
x.alpha
,会给出未定义的行为。那么给定的代码有未定义的行为?如果是这样的话,我就可以睡得好一点了。我就是这么说的。@Peter,你能给我一个答案,我就接受吗?这对我来说是有意义的,而正是给定的代码吸引了我confused@ColinHicks不,给定的代码不太可能有未定义的行为。它只有在非常奇特的系统中才会有UB,无论是
int
带有许多填充位的系统,还是1的补码或有符号幅度不允许负零的系统。对于主流托管或嵌入式系统,这段代码非常好,尽管endianess很重要。既然
char
不允许有填充位,那么它怎么可能有陷阱表示呢?@Lundin:机器可能使用符号大小或一的补码表示有符号整数,在这种情况下为“负零”可以是陷阱表示。参见6.2.6.2(2)。为什么我们不能只应用
6.5
中的一个别名规则:在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含联合的成员)。在本例中,我们有一个字符类型的成员,该成员通过包含未指定值的匿名联合进行访问
struct Scope 
{ 
    union
    { 
        int num; 
        uint8_t num_byte [sizeof(int)];
    }; 
    int foo;
};