岔路口、未定义行为(undefined behavior,ub行为)

By | 2015年12月27日

在上一篇文章中我们说到,不应该在一个表达式内进行多个“自增”,“自减”操作

原因是这是一个未定义行为,那么什么是未定义行为呢?

在C语言标准中,有一类行为没有被规定,这样一些行为便是未定义行为(Undefined Behavior,有时称为UB或UB行为)

如果你的程序中有未定义行为,那么这个程序的结果不是确定的。换句话说,就是你的程序在不同的编译器上可能会得到完全不同的结果(例如上一篇文章中的例子)。

那么你可能会为,那么为什么c标准不对这些行为做出规定呢?难道是疏漏么?

答案是否定的,规定的制定者们早就考虑到了这些问题。然而相对于将这些行为确定下来,对这些行为不做规定似乎是一个更好的选择,因为它给编译器对程序进行优化提供了空间

毕竟,c语言相比其它语言的一大特点便是更高的执行效率,用几个UB行为来换取更高的效率,在一定程度上或许是可以接受的。

或许,“未定义行为”是一个失败的翻译,倘若将其翻译为“不定义行为”,才是其真实的意义 :mrgreen:

那么有哪些未定义行为呢?

一个很常见的未定义行为便是在一个表达式中修改了某一个值,而这个值又在该表达式中被使用

例如:

int foo = 0;
foo += foo++;

将这个表达式展开后,你将得到foo = foo + foo++;

这样问题便来了,如果编译器先计算+=左边的值,即0,接着再计算foo++,它的值也是0,而foo则是1。0+0,你最后将得到0

如果先计算foo++,它的值是0,而foo则成了1,这时若再将两者相加,你将得到1+0也就是1这个结果

不同的计算顺序将得到不同的结果,而C标准中正好没有对此进行规定

另一个例子是

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int foo = 0;
	printf("%d %d %d", foo, foo++, foo);
	return 0;
}

你认为输出结果会是什么呢?

0 0 0么?1 0 0或者0 0 1?

然而答案是都不是!

如果你使用gcc编译器,你将得到1 0 1,如下图

ub

没错,这也是一个未定义行为!

显然,你的程序中如果有未定义行为,或许正如语言标准所说,“什么事情都可能发生”。当然也许什么都没有发生。

未定义行为并不是严格意义上的错误,因为人家是符合语法的。而且c语言标准也并没有要求编译器去检查这些未定义行为

因此,你应该将这些行为熟记于心,并远离它们

未定义行为还有好多,我们将在后面学习新知识的时候指出,请留心!

发表评论

邮箱地址不会被公开。 必填项已用*标注