什麼是未定義行為?
本文將講述未定義行為(Undefined Behavior, UB)與相關概念,包括:實現定義行為(Implementation-Defined Behavior)、非良構行為(Ill-Formed Behavior)。
未定義行為是指運行C++ 標準規定爲未定義的代碼時,結果可能無法預測,也沒有保證。這意味著程序可能:
- 正常執行,但結果不正確;
- 崩潰;
- 表現出看似隨機的行為;
- 引發任何其他不可預知的結果。
通俗來說,未定義行爲是一種不受限制的⌈實現定義⌋。
不少初學者遇到的難以理解的問題都是因爲使用到了未定義行爲,
未定義行為的存在是因為 C++ 的設計選擇:
- 性能優化:允許編譯器假設程序不會觸發未定義行為,可以進行更激進的優化,而不必為處理無效代碼負責。
- 支援不同的硬體架構:未定義行為允許語言適應不同硬件特性,避免標準對行為進行不必要的限制。
實現定義與未定義行為的區別
實現定義行為(Implementation-Defined Behavior)是指行為的具體結果由編譯器或運行環境決定,但必須在文檔中明確說明。如:
- 整數類型的大小(如
int是否為 32 位或 64 位)。 - 移位操作對負數的行為。
簡而言之,實現定義者需要爲行爲的效果提供文檔說明,且保證按預期執行。
非良構行為的概念
除了未定義行為與實現定義行為,C++ 還有一個相關概念:非良構行為(Ill-formed Behavior)。這通常是指程序的代碼不符合語法或語義規則,無法通過編譯。
範例:
int x = "hello"; // 非良構,類型不匹配與非良構行為不同,未定義行為在語法上可能是合法的,但其執行結果未被標準規定。
常見的未定義行為
以下是一些典型的未定義行為例子:
訪問已被釋放的內存
int* ptr = new int(42); delete ptr; int value = *ptr; // 未定義行為沒有順序保證的變數修改
int i = 0; int x = i++ + i++; // 未定義行為,無保證先執行哪個操作數組越界訪問
int arr[5] = {1, 2, 3, 4, 5}; int value = arr[10]; // 未定義行為
未定義行爲具有以下問題:
難以調試:UB 的後果不可預測,可能僅在特定條件下表現為錯誤。安全漏洞:UB 是許多安全漏洞的根源,如越界訪問可能導致緩衝區溢出。移植性問題:不同平台的行為可能不同,不同編譯器,乃至同一編譯器的不同版本都可能不同。
總結
- 非良構行爲:通常代表代碼不符合語法或語義規則,無法通過編譯。
- 實現定義行爲: 行為的結果由編譯器或環境決定,但受到控制與保障。
- 未定義行爲: 無保證且不受任何限制的⌈實現定義⌋。
參閱:
文章结构紧凑,层次分明,逻辑严密,让人一读即懂。