在线文档教程
C++
语言 | Language

Undefined behavior

未定义行为

如果语言的某些规则被违反,整个程序就会变得毫无意义。

解释

C++标准精确地定义了可观察行为对于不属于以下类之一的每个C++程序:

  • 畸形-程序有语法错误或可诊断的语义错误。一个符合标准的C++编译器需要发出诊断,即使它定义了一个语言扩展,该扩展为这样的代码%28指定了意义,比如使用可变长度数组%29。标准文本使用,,,不得,和畸形以表明这些要求。

  • 不需要诊断-程序有语义错误,一般情况下不能诊断。违反ODR或仅在链接时间%29可检测到的其他错误。如果执行这样的程序,则该行为是未定义的。

  • 实现-定义的行为-程序的行为因实现而异,符合的实现必须记录每种行为的效果。例如,std::size_t或字节中的位数,或std::bad_alloc::what实现定义行为的子集是特定地区行为,这取决于提供的实现。现场...

  • 未指定行为-程序的行为因实现而异,不需要符合的实现来记录每种行为的效果。例如,评价顺序,是否相同字符串文字数组分配开销的大小等等。每个未指定的行为都会产生一组有效的结果之一。

  • 未定义行为-对该方案的行为没有任何限制。未定义行为的例子有:数组边界外的内存访问、带符号整数溢出、空指针取消引用、对同一个标量的修改。不止一次在没有序列点的表达式中,通过不同类型的指针访问对象,等等。编译器不需要诊断未定义的行为%28,尽管许多简单的情况被诊断为%29,并且编译的程序不需要做任何有意义的事情。

UB与优化

由于正确的C++程序不存在未定义的行为,因此,当实际具有UB的程序在启用优化的情况下编译时,编译器可能会产生意外的结果:

例如,

符号溢出

二次

int foo(int x) { return x+1 > x; // either true or UB due to signed overflow }

二次

可以编译为%28演示29%。

二次

foo(int): movl $1, %eax ret

二次

出界

二次

int table[4] = {}; bool exists_in_table(int v) { // return true in one of the first 4 iterations or UB due to out-of-bounds access for (int i = 0; i <= 4; i++) { if (table[i] == v) return true; } return false; }

二次

可以编译为%28演示29%。

二次

exists_in_table(int): movl $1, %eax ret

二次

未初始化标量

二次

std::size_t f(int x) { std::size_t a; if(x) // either x nonzero or UB a = 42; return a; }

二次

可以编译为%28演示29%。

二次

f(int): mov eax, 42 ret

二次

在早期版本的GCC上观察到了所显示的输出。

二次

bool p; // uninitialized local variable if(p) // UB access to uninitialized scalar std::puts("p is true" if(!p) // UB access to uninitialized scalar std::puts("p is false"

二次

可能的产出:

二次

p is true p is false

二次

访问传递给realloc的指针

选择clang来观察所显示的输出。

二次

#include <iostream> #include <cstdlib> int main() { int *p = (int*)std::malloc(sizeof(int) int *q = (int*)std::realloc(p, sizeof(int) *p = 1; // UB access to a pointer that was passed to realloc *q = 2; if (p == q) // UB access to a pointer that was passed to realloc std::cout << *p << *q << '\n'; }

二次

可能的产出:

二次

12

二次

无副作用的无限循环

选择clang来观察所显示的输出。

二次

#include <iostream> int fermat() { const int MAX = 1000; int a=1,b=1,c=1; // Endless loop with no side effects is UB while (1) { if (((a*a*a) == ((b*b*b)+(c*c*c)))) return 1; a++; if (a>MAX) { a=1; b++; } if (b>MAX) { b=1; c++; } if (c>MAX) { c=1;} } return 0; } int main() { if (fermat()) std::cout << "Fermat's Last Theorem has been disproved.\n"; else std::cout << "Fermat's Last Theorem has not been disproved.\n"; }

二次

可能的产出:

二次

Fermat's Last Theorem has been disproved.

二次

外部链接

© cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

http://en.cppreference.com/w/cpp/language/ub