在优秀的博文What Every Programmer Should Know About Undefined Behavior中,“违规类型规则”部分说:
将一个int *转换为float *并取消引用它(访问“int”就好像它是一个“float”)是未定义的行为。 C要求通过memcpy进行这些类型的转换:使用指针强制转换不正确并导致未定义的行为。对此的规则是非常细微的,我不想在这里详细说明(char *有例外,向量有特殊属性,工会改变事物等)。
我想了解他们完全细微差别的规则。他们在C ++ 11规范中的位置是什么?或者失败了,C规范(C90,C99,C11)?
在从this Stack Overflow question,N3485链接的C ++ 11规范中,我正在查看5.2.10“重新解释强制转换”,但是没有看到char *或联合的例外语言。所以这可能不是正确的地方。那么正确的地方在哪里?
答案 0 :(得分:4)
您正在寻找的规则是§3.10/ 10(在C ++ 11中):
如果程序试图访问对象的存储值 通过以下类型之一以外的glvalue 行为未定义: - 对象的动态类型,
- 对象的动态类型的cv-quali fi ed版本,
- 与对象的动态类型相似的类型(如4.4中所定义的),
- 与对象的动态类型对应的有符号或无符号类型, - 对应于动态类型的cv限定版本的有符号或无符号类型 对象,
- 聚合或联合类型,包括其元素中的上述类型之一或非静态类型 数据成员(包括,递归地,子集合的元素或非静态数据成员 或包含联盟),
- 一种类型,是对象动态类型的(可能是cv-quali fi ed)基类类型,
- char或unsignedchar类型。
undefined有不同的类型(或动机) 行为。
如果将int*
投射到float*
然后再投射
解除引用它,很明显标准无法定义
它,因为可能发生的将取决于架构,和
int
的值。另一方面,引用的段落
完全错误 - 使用memcpy
进行转换是
也是未定义的行为,原因大致相同。
未定义行为的动机之一是
允许实现以有意义的方式定义它
对于目标体系结构,如果存在。就是这样
一件事。故意使其失败的编译器是
有缺陷的。当然,如果我们假设32位2的补码
int
和32位IEEE float
,我们可以预期某些值
int
对应于捕获NaN,这将导致程序
失败。这是行为的部分原因
不确定的;允许这样的事情发生。但如果我们是
熟悉硬件的低级细节,
应该按预期工作,提供编译器可以看到
演员。
如果没有,这是编译器的QoI问题,等等
对于此类工作,应避免使用编译器。
如上所述,这个特殊情况,事实上,在所有情况下
涉及打字的案件(写给一名成员)
一个联盟,并从另一个人那里读书,确实有姿势
一个问题,标准尚未找到足够的问题
措辞。出现问题的原因通常是编译器
允许假设指向不同类型的指针(除了
字符类型)别别名; int*
永远无法指向的人
与float*
相同的对象。并证明了两个指针
不能别名对于优化很重要。一个编译器
中断指针转换或联合清晰可见的代码
刚破坏,即使标准说它是未定义的行为。
一个破坏代码的编译器,它所看到的只是两个指针
对于不相关的类型是可以理解的,即使在这种情况下也是如此
标准说行为定义明确。
使用memcpy
通过使用两个不同的方法来避免此问题
对象,不用别名。它仍然遇到未定义
行为,因为将int
的位模式放入
一个float
,然后访问浮动,没有任何定义
行为。 (反之亦然;我知道至少有一台机器在哪里
将float
的位复制到int
可能会导致
非法int
值。)
答案 1 :(得分:1)
C ++标准说如果没有明确地描述某个行为被定义,那么它是隐式未定义的。由于标准没有定义将int*
转换为float*
的行为,因此隐式未定义。
答案 2 :(得分:0)
reinterpret_cast
是根据static_cast
指针void
定义的
5.2.10重新解释cast [expr.reinterpret.cast]>
7可以将对象指针显式转换为对象指针 一种不同的类型。 70当“指向T1的指针”类型的prvalue v为 转换为“指向cv T2的指针”类型,如果T1和T2都是标准布局,则结果为
static_cast<cv T2*>(static_cast<cv void*>(v))
类型(3.9)和T2的对齐要求不比更严格 T1的那些,或者如果任何一种类型无效。转换类型的prvalue “指向T1的指针”到“指向T2的指针”(其中T1和T2为 对象类型以及T2的对齐要求为否 比T1更严格,并回到原来的类型产生 原始指针值。任何其他此类指针的结果 转换未指定。
5.2.9静态演员[expr.static.cast]
13类型“指向cv1 void的指针”的prvalue可以转换为a 类型为“指向cv2 T的指针”的prvalue,其中T是对象类型和cv2 与cv1相同的cv-quali fi cation或更高的cv-quali fi cation。 空指针值转换为空指针值 目的地类型。转换为对象的类型指针的值 “指向cv void”并返回,可能具有不同的cv-quali fi cation, 应具有原始价值。