©
本文档使用 PHP中文网手册 发布
C语言标准精确地规定了C语言程序的可观察行为,除了以下几类:
未定义的行为 - 对程序的行为没有限制。未定义行为的例子是数组边界之外的内存访问,有符号整数溢出,空指针取消引用,在没有序列点的表达式中多次修改相同标量,通过不同类型的指针访问对象等。编译器不需要诊断未定义的行为(虽然诊断了许多简单情况),编译后的程序不需要做任何有意义的事情。
未指定的行为 - 允许两个或更多行为,并且不需要实现来记录每个行为的影响。例如,评估顺序,相同的字符串文字是否不同等。每个未指定的行为都会导致一组有效结果中的一个,并且在同一程序中重复时可能会产生不同的结果。
实现定义的行为 - 未指定的行为,其中每个实现记录如何进行选择。例如,一个字节中的位数,或者有符号整数右移是算术还是逻辑。
特定于语言环境的行为 - 实现定义的行为取决于当前选择的语言环境。例如,对于islower
除26个小写拉丁字母以外的任何字符,是否返回true。
(注意:严格符合的程序不依赖于任何未指定的,未定义的或实现定义的行为)。
编译器需要为任何违反C语法规则或语义约束的程序发布诊断消息(错误或警告),即使其行为被指定为未定义或实现定义的,或者编译器提供了允许它的语言扩展接受这样的计划。对未定义行为的诊断不是必需的。
由于正确的C程序没有未定义的行为,因此编译器可能会在实际具有UB的程序在启用优化的情况下编译时产生意外的结果:
例如,
int foo(int x) { return x+1 > x; // either true or UB due to signed overflow}
可能被编译为(演示)。
foo(int): movl $1, %eax ret
int table[4] = {};int 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 1; } return 0;}
可以编译为(演示)。
exists_in_table(int): movl $1, %eax ret
bool p; // uninitialized local variableif(p) // UB access to uninitialized scalar puts("p is true");if(!p) // UB access to uninitialized scalar puts("p is false");
可能产生以下输出(用旧版本的gcc观察):
p is truep is false
size_t f(int x){ size_t a; if(x) // either x nonzero or UB a = 42; return a; }
可以编译为(演示)。
f(int): mov eax, 42 ret
选择clang以观察显示的输出。
#include <stdio.h>#include <stdlib.h>int main(void) { int *p = (int*)malloc(sizeof(int)); int *q = (int*)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 printf("%d%d\n", *p, *q);}
可能的输出:
12
选择clang以观察显示的输出。
#include <stdio.h> 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(void) { if (fermat()) puts("Fermat's Last Theorem has been disproved."); else puts("Fermat's Last Theorem has not been disproved.");}
可能的输出:
Fermat's Last Theorem has been disproved.
C11标准(ISO / IEC 9899:2011):
3.4行为(p:3-4)
4/2未定义的行为(p:8)
C99标准(ISO / IEC 9899:1999):
3.4行为(p:3-4)
4/2未定义的行为(p:7)
C89 / C90标准(ISO / IEC 9899:1990):
1.6术语定义