未定义的行为Clang vs gcc vs VC



我在计算机上尝试了C/C++中的一些未定义的行为示例,以查看它们在每次运行代码时是否确实给出了不同的结果。我注意到,在同一个编译器中,所有的运行都给出了相同的结果。所以我的第一个问题是,这种行为真的没有定义吗?

第二个问题:为什么当我把编译器从clang改为vs时,结果会改变?造成这种情况的根本原因是什么?

示例1:

#include <stdio.h>
int main (int argc, char *argv[])
{
int i = 1;
int v = 2;
i = i++ + v;
printf("%dn", i);
return 0;
}

在Clang和gcc中,结果总是3。而在vc中,结果总是4。

另一个整数溢出的例子:

int main (int argc, char *argv[])
{
int i = 1;
int v = 2;
i = i++ + v;
printf("%dn", i);

return 0;
}

Clang总是给出一个完全不同的结果(我认为这是未定义的行为(,而gcc总是给出相同的结果——2147483648。

我预计结果会根据他们使用的机器而有所不同(例如2补码(,而不是在编译器之间有所不同。

简而言之,我的问题是:1(未定义的行为是什么?2(为什么编译器的结果不同?

这真的是未定义的行为吗?

在C++17是之前,行为是未定义的。自C++17以来,该行为已得到很好的定义。

为什么当我把编译器从clang改为vs时,结果会改变?

造成这种情况的根本原因是什么?

2( 为什么不同编译器的结果不同?

因为程序的行为是未定义的。

由于C++17,正确的行为是输出3。如果编译器产生不同的行为,则它不符合C++17(您可能需要显式启用C++17一致性(。

1(未定义行为的含义

这意味着程序可以有任何、全部或没有特定的行为,并且该行为在任何方面都不受标准的约束。


我注意到在同一个编译器中,所有的运行都给出了相同的结果。

请注意,当行为未定义时,这是不能保证的。

还要注意,未定义的行为并不能保证所有的运行都不会给你相同的结果。

甚至不能保证你会得到任何结果。


我预计结果会因的机器而异

请注意,未定义的行为并不能保证结果会因机器而异。

不要因编译器而异。

不能保证未定义的行为在编译器之间不会发生变化。

如果不清楚:当程序未定义时,程序的行为不会得到任何保证

我在电脑上尝试了一下,看看每次运行代码时它们是否真的给出了不同的结果。

这不是未定义行为的定义。

未定义的行为是什么意思?

当某个条件未被标准覆盖或标准明确报告为未定义行为时,会发生未定义行为。在这种情况下,编译器可以随心所欲地执行。由于编译器是确定性程序,因此在同一环境中使用同一编译器的同一版本编译同一代码很可能会产生相同的结果。这完全是"正常的"。未定义的行为并不意味着输出将在每次执行时发生更改,尽管它肯定

有关更多信息,请参见C99标准第492页J.2段中"未定义行为"的定义。

为什么不同编译器的结果不同?

根据定义,未定义行为不应用任何限制或强制任何特定行为,因此任何编译器都可以随心所欲地解释源代码,并产生任何想要的结果。这就是为什么未定义行为是一种非常危险的野兽的首要原因。即使是同一编译器的不同版本也可能有不同的行为。

编译器通常假设未定义的行为永远不会发生,因此对程序进行假设,以便能够更好地优化它,甚至能够发出代码。导致未定义的行为可能会打破这些假设,并导致编译器发出与程序员所想的完全不同的代码。

最新更新