【发布时间】:2015-11-14 02:22:22
【问题描述】:
在 3.19.3 p1 中,C11 说未指定的值不能是陷阱表示,但我不明白什么值既不是陷阱表示又是未指定的。
顺便说一句,我也想知道编译器如何知道对象表示是否是陷阱表示?
【问题讨论】:
标签: c language-lawyer c11
在 3.19.3 p1 中,C11 说未指定的值不能是陷阱表示,但我不明白什么值既不是陷阱表示又是未指定的。
顺便说一句,我也想知道编译器如何知道对象表示是否是陷阱表示?
【问题讨论】:
标签: c language-lawyer c11
这是控制和数据的区别。
未指定的值可能会导致结果中出现意外值(函数返回、分配给全局变量等)。但是你的程序的正常控制流程仍然会被遵循。
另一方面,陷阱表示可能会导致您使用分支语句(函数调用、条件、循环、goto、返回)未描述的控制流。
一个典型的例子是 IEEE 754 中的信号 NaN。根据 FPU 控制字,遇到信号 NaN 会导致立即传输到异常处理程序(又名软件中断又名信号)。
【讨论】:
术语定义
未指定的行为 — 行为,用于正确的程序结构和正确的数据,标准对此没有任何要求。
未定义行为 — 使用不可移植或错误程序结构、错误数据或不确定值对象的行为,标准对此没有任何要求.
在构造一个const对象的过程中,如果对象的值 或其任何子对象通过不 从构造函数的 this 指针直接或间接获得, 由此获得的对象或子对象的值是未指定的。
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
int i = cobj.c * 100; // value of cobj.c is unspecified
cptr->c = 1;
cout << cobj.c * 100 // value of cobj.c is unspecified
<< ’\n’;
}
在上面的示例中,没有未初始化的值,因此没有陷阱表示,但标准没有授予(指定)其行为。上面示例中的编译器可以对其进行任何处理,即不同的编译器会给出不同的结果。
英文术语或多或少是逐字使用的:“未指定”表示 标准没有给出精确的语义,但是 程序不会变得未定义或格式错误。
陷阱表示是一组位,当解释为 特定类型的值会导致未定义的行为。陷阱 表示最常见于浮点和指针 值,但理论上,几乎任何类型都可能有陷阱 申述。未初始化的对象可能包含陷阱 表示。这给出了与旧规则相同的行为:访问 未初始化的对象会产生未定义的行为。
举个例子:
unsigned char a, b;
memcpy(&a, &b, 1);
a -= a;
a和b的地址,所以它们的值只是不确定的。unsigned char 从未有过不确定值只是未指定的陷阱表示,因此unsigned char 的任何值都可能发生。a 必须保持值0。a 和 b 具有未指定的值:
3.19.3 未指定值
本国际标准对在任何情况下选择哪个值没有要求的相关类型的有效值
【讨论】:
unsigned char 是 8 位,则 a-a 的值可以是 -255 到 +255 之间的任何值,并且在上述 a 之后可以保持任何值。我认为表达式的结果将是 Unspecified 而不是 Indeterminate,但我不确定。