C 在不可到达路径上具有未定义行为的程序的行为是否已定义?

C 在不可到达路径上具有未定义行为的程序的行为是否已定义?,c,language-lawyer,undefined-behavior,C,Language Lawyer,Undefined Behavior,考虑 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

考虑

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;
}
swap
是一种试图欺骗编译器不优化程序的行为


是否定义了该程序的行为<代码>a/b永远无法访问,但如果是,则会得到一个除零的结果。

未计算表达式的行为与程序的行为无关。如果对表达式求值,则未定义的行为与程序的行为无关

如果是这样的话,那么这段代码就没用了:

if (p != NULL)
    …; // Use pointer p.

(您的XOR可能具有未定义的行为,因为它们可能会产生陷阱表示。您可以通过将对象声明为易失性来击败此类学术示例的优化。如果对象是易失性的,C实现无法知道其值是否会因外部手段而改变,因此每次使用该对象都需要实现阅读它的价值。)< P/> > P>,在这个问题上,没有必要把任何一个给定的代码构造或实践的有用性,也不基于C++的任何东西,无论是在标准中还是在另一个答案中,无论C++的定义有多相似。 使用不可移植或错误的程序结构时的行为,或 本国际标准没有规定的错误数据 要求

(C2011,3.4.3/1;增加强调)

因此,未定义的行为是临时触发的(“在使用”一个结构或数据时),而不仅仅是存在。*这对于由数据产生的未定义行为和由程序结构产生的未定义行为来说是一致的,这是很方便的;标准不必在那里保持一致。正如另一个答案所描述的,这是“在使用时”定义是一个很好的设计选择,因为它允许程序避免执行与错误数据相关的未定义行为

另一方面,如果程序确实执行未定义的行为,那么根据标准的定义,程序的整个行为都是未定义的。这种随之产生的未定义是一种更普遍的类型,因为与错误数据或构造直接相关的UB原则上可能包括更改程序的其他部分的行为,甚至追溯(或显然如此)。当然,对可能发生的事情有语言外的限制——因此,不,鼻魔实际上不会出现——但它们不一定像人们想象的那么强烈



*警告:一些程序结构在翻译时使用。这些结构在程序翻译时产生UB,结果是程序的每次执行都有完全未定义的行为。举个有点愚蠢的例子,如果程序源代码没有以未转换的换行符结尾,则程序的行为完全未定义(见,第2点).

一般来说,如果执行将调用未定义行为的代码,如果未执行,则该代码不得产生任何效果。然而,在一些情况下,现实世界的实现可能会以相反的方式运行,并拒绝生成代码,而这些代码虽然不违反约束,但不可能以定义的行为执行

extern struct foo z;

int main(int argc, char **argv)
{
    if (argc > 2) z;
    return 0;
}

根据我对该标准的理解,它明确地将不完整类型上的左值转换描述为调用未定义的行为(除其他外,还不清楚实现可以为这种行为生成什么代码),因此,如果
argc
等于或大于3,则该标准不会对行为施加任何要求。但是,我无法确定标准中上述代码会违反的任何约束,如果
argc
等于或小于2,则不应完全定义任何原因行为。尽管如此,包括gcc和clang在内的许多编译器都拒绝上述co完全删除。

我对UB的理解是,它需要到达一条不可避免地导致包含UB的表达式的路径。也就是说,只要有可能未到达包含UB的表达式,就没有UB。尽管我找不到源代码。否则,在ca之前检查
nullptr
等常见策略LILL成员函数将是UB。@弗兰Cou.Osand Reunix,我想UB是在什么时候,也只有当表达式的路径被取下的时候。@席:在C++标签上。我在C标签上问了这个问题,因为C.@你的规则一般都比较简单。这个问题是要求把UB引入分支中就足以迫使编译器假设。这个分支是不可到达的。“C,C++可能是或者可能没有相同的定义,因为C++是答案的一部分,我认为C和C++是分开的语言,它们随着时间的流逝而变得越来越分散,从我所理解的,没有任何东西说它们必须有相同的行为,所以我认为关闭作为C++问题的副本是近似的。riate.注意,如果可以证明最终会到达一个带有UB的表达式,那么它并不一定会导致UB。@FrançoisAndrieux这并不清楚它的意思。C程序通常是确定的。如果在特定的运行中(使用确定的输入/时间和/或
rand
output)可以到达一条路径,它将被到达。@EugeneSh。我的意思是,如果可以证明一条路径在所有条件下都指向一个带UB的表达式,那么程序就有UB。也就是说,如果在给定的点上可以证明所有路径都指向UB,那么程序在该点上就已经是UB了。编译器可以做出该决定并相应地采取行动,在已达到实际UB表达式。@Bathsheba:如果您认为这会改善问题,请继续编辑。如果需要,请编辑一些答案。我可以稍后再查看。现在必须开始。@ruakh在这种情况下,UB表达式不是无法访问的错误报告分支不会返回或以其他方式阻止通过t继续控制他发挥作用,因此控制权被假定为eve