?
This document uses PHP Chinese website manual Release
C語言標(biāo)準(zhǔn)精確地規(guī)定了C語言程序的可觀察行為,除了以下幾類:
未定義的行為 - 對(duì)程序的行為沒有限制。未定義行為的例子是數(shù)組邊界之外的內(nèi)存訪問,有符號(hào)整數(shù)溢出,空指針取消引用,在沒有序列點(diǎn)的表達(dá)式中多次修改相同標(biāo)量,通過不同類型的指針訪問對(duì)象等。編譯器不需要診斷未定義的行為(雖然診斷了許多簡(jiǎn)單情況),編譯后的程序不需要做任何有意義的事情。
未指定的行為 - 允許兩個(gè)或更多行為,并且不需要實(shí)現(xiàn)來記錄每個(gè)行為的影響。例如,評(píng)估順序,相同的字符串文字是否不同等。每個(gè)未指定的行為都會(huì)導(dǎo)致一組有效結(jié)果中的一個(gè),并且在同一程序中重復(fù)時(shí)可能會(huì)產(chǎn)生不同的結(jié)果。
實(shí)現(xiàn)定義的行為 - 未指定的行為,其中每個(gè)實(shí)現(xiàn)記錄如何進(jìn)行選擇。例如,一個(gè)字節(jié)中的位數(shù),或者有符號(hào)整數(shù)右移是算術(shù)還是邏輯。
特定于語言環(huán)境的行為 - 實(shí)現(xiàn)定義的行為取決于當(dāng)前選擇的語言環(huán)境。例如,對(duì)于islower
除26個(gè)小寫拉丁字母以外的任何字符,是否返回true。
(注意:嚴(yán)格符合的程序不依賴于任何未指定的,未定義的或?qū)崿F(xiàn)定義的行為)。
編譯器需要為任何違反C語法規(guī)則或語義約束的程序發(fā)布診斷消息(錯(cuò)誤或警告),即使其行為被指定為未定義或?qū)崿F(xiàn)定義的,或者編譯器提供了允許它的語言擴(kuò)展接受這樣的計(jì)劃。對(duì)未定義行為的診斷不是必需的。
由于正確的C程序沒有未定義的行為,因此編譯器可能會(huì)在實(shí)際具有UB的程序在啟用優(yōu)化的情況下編譯時(shí)產(chǎn)生意外的結(jié)果:
例如,
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");
可能產(chǎn)生以下輸出(用舊版本的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標(biāo)準(zhǔn)(ISO / IEC 9899:2011):
3.4行為(p:3-4)
4/2未定義的行為(p:8)
C99標(biāo)準(zhǔn)(ISO / IEC 9899:1999):
3.4行為(p:3-4)
4/2未定義的行為(p:7)
C89 / C90標(biāo)準(zhǔn)(ISO / IEC 9899:1990):
1.6術(shù)語定義