在优秀的博客文章中每个程序员都应该了解关于未定义行为的知识 http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html,“违反类型规则”部分说:
将 int* 转换为 float* 并取消引用它(访问“int”就好像它是“float”一样)是未定义的行为。 C 要求通过 memcpy 进行此类类型转换:使用指针强制转换是不正确的,并且会导致未定义的行为。其规则非常微妙,我不想在这里详细介绍(char* 有一个例外,向量具有特殊属性,联合会改变事物等)。
我想全面了解这些规则的细微差别。它们在 C++11 规范中的什么位置?或者如果做不到这一点,C 规范(C90、C99、C11)?
在链接自的 C++11 规范中这个堆栈溢出问题 https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents,N3485,我正在查找 5.2.10“重新解释强制转换”,但没有看到 char* 或联合的异常语言。所以那可能不是正确的地方。那么正确的地方在哪里呢?
您要查找的规则位于 §3.10/10(在 C++11 中):
如果程序尝试访问对象的存储值
通过除以下类型之一之外的左值
行为未定义:
— 对象的动态类型,
— 对象动态类型的 cv 限定版本,
— 与对象的动态类型类似的类型(如 4.4 中定义),
— 与对象的动态类型相对应的有符号或无符号类型,
— 与动态类型的 cv 限定版本相对应的有符号或无符号类型
的物体,
— 聚合或联合类型,其元素或非静态中包含上述类型之一
数据成员(递归地包括子聚合的元素或非静态数据成员
或包含联合),
— 一个类型,它是对象动态类型的(可能是 cv 限定的)基类类型,
— char 或 unsigned char 类型。
未定义有不同的类型(或动机)
行为。
在铸造的情况下int*
to float*
进而
取消引用它,很明显该标准无法定义
它,因为可能发生的情况取决于架构,并且
的价值int
。另一方面,引用的段落
是完全错误的——使用memcpy
进行转换是
出于大致相同的原因,还有未定义的行为。
未定义行为的动机之一是
允许实现以有意义的方式定义它
对于目标架构,if这样的存在。这是这样的
一个案例。故意导致其失败的编译器是
有缺陷的。当然,如果我们假设 32 位 2 的补码int
和 32 位 IEEEfloat
,我们可能期望某些值
这int
对应于捕获NaN,这将导致程序
失败。这是该行为的部分原因
不明确的;允许这样的事情发生。但如果我们是
熟悉硬件的底层细节,
它should按预期工作,provided编译器可以看到
演员阵容。
如果没有,这是编译器的 QoI 问题,诸如此类
应避免使用编译器来完成此类工作。
正如上面所暗示的,这个特殊情况,事实上,在所有情况下
涉及类型双关的案例(写信给
例如,一个联盟,并从另一个联盟那里阅读),请摆出姿势
该标准尚未找到充分解决的问题
措辞。出现这个问题的原因是编译器通常是
允许假设指向不同类型的指针(除了
字符类型)不要别名;那一个int*
永远不能指向
与 a 相同的对象float*
。并证明两个指针
不能使用别名对于优化很重要。一个编译器
破坏指针转换或联合清晰可见的代码
只是被破坏了,即使标准说这是未定义的行为。
编译器会破坏代码,它所看到的只是两个指针
不相关的类型是可以理解的,即使在
标准表示该行为已明确定义。
Using memcpy
通过使用两种不同的方式避免了这个问题
没有别名的对象。还是遇到未定义的情况
行为,因为将位模式int
into
a float
,然后访问浮动,没有任何定义
行为。 (反之亦然;我知道至少有一台机器
复制 a 的位float
进入一个int
可能会导致
非法的int
value.)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)