我已经搜索了一段时间,但找不到明确的答案.

很多人说,使用unions 来输入双关语是不明确的,也是不好的做法.这是为什么?我看不出为什么它会做任何未定义的事情,因为您将原始信息写入的内存不会自动改变(除非它超出堆栈的范围,但这不是联合问题,这将是糟糕的设计).

人们引用严格的别名规则,但在我看来,这就像是说你不能做,因为你做不到.

另外,如果不打双关语,unions 还有什么意义呢?我在某个地方看到,它们应该用来在不同的时间对不同的信息使用相同的内存位置,但是为什么不在再次使用之前直接删除这些信息呢?

总结一下:

  1. 为什么使用联合体进行类型双关语是不好的?
  2. 如果不是这样,他们又有什么意义呢?

额外信息:我主要使用C++,但我想了解一下这一点和C语言.具体地说,我使用联合在浮点数和原始祸不单行之间进行转换,以便通过CAN总线发送.

推荐答案

要重新迭代,通过联合进行类型双关在C中是完全可以的(但在C++中则不行).相比之下,使用指针强制转换违反C99严格的别名,这是有问题的,因为不同的类型可能有不同的对齐要求,如果操作错误,可能会引发SIGBUS.对于unions 来说,这从来都不是问题.

C标准中的相关引用如下:

C89第3.3.2.3节第5节:

如果在将值存储在联合对象的其他成员之后访问该联合对象的成员,则行为由实现定义

C11第6.5.2.3节§3:

后缀表达式,后跟.运算符和标识符指定 struct 或联合对象的成员.该值是命名成员的值

脚注95如下:

如果用于读取联合对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的适当部分将重新解释为6.2.6中所述的新类型中的对象表示(有时称为"类型双关"的过程).这可能是一个trap .

这应该非常清楚.


詹姆斯感到困惑,因为C11第6.7.2.1§16节

最多一个成员的值可以随时存储在联合对象中.

这似乎是矛盾的,但它不是:与C++相比,在C中,没有活动成员的概念,通过不兼容类型的表达式访问单个存储值是完全正确的.

另见C11附件J.1第1节:

与联合成员相对应的字节值(上次存储到[中的字节除外)未指定.

在C99中,它用于读取

存储到[中的最后一个成员以外的联合成员的值未指定]

这是不正确的.由于附件不是标准化的,它没有对自己的TC进行评级,不得不等到下一次标准修订时才能得到修复.


标准C++(和C90)do explicitly allow type-punning with unions的GNU扩展.其他不支持GNU扩展的编译器可能也支持联合类型双关,但它不是基本语言标准的一部分.

C++相关问答推荐

单指针和空参数列表之间的函数指针兼容性

如何在Visual Studio代码中关闭此函数名称显示功能?

特定闪存扇区的内存别名

ARM64 ASIMD固有的加载uint8_t* 到uint16x8(x3)?

致命:ThreadSaniizer:在Linux内核6.6+上运行时意外的内存映射

解决S随机内存分配问题,实现跨进程高效数据共享

为什么我的Hello World EFI程序构建不正确?

FRIDA-服务器成为端口扫描的目标?

在C中访问数组中的特定值

按长度对argv中的单词进行排序

循环中的静态变量与块中的变量和循环

不使用任何预定义的C函数进行逐位运算

OSDev--双缓冲重启系统

当我用scanf(&Q;%S%S%S&Q;,单词0,单词1,单词2)输入多个单词时,除了最后一个单词外,每个单词的第一个字符都丢失了

不确定如何处理此编译错误

为什么二进制文件的大小不会随着静态数据的大小而增加?

变量值不正确的问题

atoi函数最大长-长误差的再创造

Makefile - 将 .o 文件放入子文件夹中

初始化动态分配的布尔二维数组的最佳方法是什么?