c - 为什么类型双关语被认为是 UB?
问题描述
想象一下:
uint64_t x = *(uint64_t *)((unsigned char[8]){'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'});
我读过这样的双关语是未定义的行为。为什么?从字面上看,我将 8 个字节的字节重新解释为 8 个字节的整数。我看不出这与 a 有什么不同,union
除了类型双关语是未定义的行为而union
s 不是?我亲自问过一个程序员同事,他们说如果你这样做,要么你知道你在做什么,要么你犯了一个错误。但是社区说应该始终避免这种做法?为什么?
解决方案
最终的原因是“因为语言规范是这样说的”。你不必为此争论。如果这就是语言的方式,那就是它的方式。
如果您想知道这样做的动机,那就是原始 C 语言缺乏任何表达两个左值不能相互别名的方式(并且restrict
大多数语言用户仍然几乎不理解现代语言的关键字) . 不能假设两个左值不能别名意味着编译器不能重新排序加载和存储,并且必须为每次访问对象时实际执行从/到内存的加载和存储,而不是将值保存在寄存器中,除非它知道对象的地址从未被占用。
C 的基于类型的别名规则通过让编译器假定具有不同类型的左值不会别名,在一定程度上缓解了这种情况。
另请注意,在您的示例中,不仅有类型双关语,还有错位。该unsigned char
数组没有固有的对齐方式,因此uint64_t
在该地址访问 a 将是一个对齐错误(UB 出于另一个原因),与任何别名规则无关。
推荐阅读
- python - 如何在 python pandas 数据框中对字符串进行分组和过滤
- python - 用列表中配对字符串之前的数字替换熊猫中的字符串
- javascript - 为什么 array.map 不返回新数组?
- php - 从 mySQL DB 检索数据时如何编写 JSON 结构?
- python-2.7 - 如何解决错误 KeyError: 'employee_id'
- php - 是否有我需要安装的包以便 atom 能够识别我的 PHP 代码?
- c# - ASP.NET Web API 以 JSON 格式显示我没有要求的对象
- javascript - 动态模块加载在 Firefox 上不起作用 - 语法错误:未实现动态模块导入
- postgresql - 如何将返回子句中的表声明为现有表的 %TYPE?
- javascript - this.setToken 不是函数