Bat*_*eba 24 c undefined-behavior language-lawyer
考虑
void swap(int* a, int* b)
{
if (a != b){
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
}
int main()
{
int a = 0;
int b = 1;
swap(&a, &b); // after this b is 0 and a is 1
return a > b ? 0 : a / b;
}
Run Code Online (Sandbox Code Playgroud)
swap 试图欺骗编译器不优化程序.
是否定义了此程序的行为?a / b是永远无法达到的,但如果是,那么你会得到除零.
Joh*_*ger 26
无论C++的定义有多么相似,无论是在标准中还是在另一个SO答案中,都没有必要根据任何给定的代码构造或实践的有用性,以及任何关于C++的任何内容来定位这个问题.要考虑的关键是C对未定义行为的定义:
行为,在使用非便携式的或错误的程序构建体的或错误的数据,其中该国际标准规定的要求没有
(C2011,3.4.3/1;重点补充)
因此,未定义的行为在时间上触发("在使用"构造或数据时),而不仅仅是存在.* 这对于数据和程序结构产生的未定义行为是一致的,这是很方便的; 标准不需要在那里保持一致.正如另一个答案所描述的那样,这种"使用后"定义是一个很好的设计选择,因为它允许程序避免执行与错误数据相关的未定义行为.
另一方面,如果程序确实执行了未定义的行为,那么从标准的定义开始,程序的整个行为是未定义的.由于直接与错误数据或构造相关联的UB原则上可以包括改变程序的其他部分的行为,甚至追溯(或显然是这样),因此这种随之而来的不确定性是更普遍的类型.对于可能发生的事情当然存在语言外的限制 - 所以不,鼻子恶魔实际上不会出现任何外表 - 但这些并不一定像人们想象的那样强烈.
*警告:一些程序结构是使用在转换时.它们在程序转换中产生UB,结果是程序的每次执行都具有完全未定义的行为.对于一个有点愚蠢的例子,如果您的程序源没有以未转义的换行结束,那么程序的行为是完全未定义的(参见C2011,5.1.1.2/1,第2点).
Eri*_*hil 22
未评估的表达式的行为与程序的行为无关.如果表达式被评估,则未定义的行为与程序的行为无关.
如果确实如此,那么这段代码就没用了:
if (p != NULL)
…; // Use pointer p.
Run Code Online (Sandbox Code Playgroud)
(您的XOR可能具有未定义的行为,因为它们可能会产生陷阱表示.您可以通过声明对象是易失性来破坏此类学术示例的优化.如果对象是易失性的,则C实现无法知道其值是否可能更改到期到外部意味着,所以每次使用对象都需要实现来读取它的值.)