基本概念
在 C++ 中,assert
是一個用於在程式執行時進行除錯的宏。它主要用於檢測程式中的假設條件是否為真,以幫助開發者發現並定位錯誤。assert 通常在除錯階段使用,而在釋出(release)版本中會被禁用,從而避免對效能產生影響。
基本用法
要使用 assert,需要包含標頭檔案 <cassert>
:
#include <cassert>
然後,可以在程式碼中使用 assert 宏來檢查一個表示式是否為真。例如:
#include <cassert>
#include <iostream>
int factorial(int n) {
assert(n >= 0); // 確保 n 是非負數
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
int number = 5;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl;
number = -3;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl; // 這裡會觸發斷言
return 0;
}
輸出如下:
在上述程式碼中,當 factorial 函式被呼叫時,如果傳入的引數 n 為負數,assert(n >= 0); 將會觸發斷言失敗,程式會中止執行並輸出錯誤資訊。
工作原理
-
除錯模式:在除錯模式下(通常未定義 NDEBUG 宏),assert 會檢查表示式的真假。如果表示式為假,程式會輸出錯誤資訊並呼叫 abort() 函式終止程式。
-
釋出模式:在釋出模式下(通常定義了 NDEBUG 宏),所有的 assert 語句都會被忽略,編譯器會將其移除。這意味著在釋出版本中,assert 不會對效能產生任何影響。
要在釋出模式中禁用 assert,可以在編譯時定義 NDEBUG 宏,例如:
g++ -DNDEBUG -o my_program my_program.cpp
補充(使用DEBUG宏)
在程式碼中定義DEBUG宏
直接在程式碼中定義DEBUG宏時,如下:
#include <cassert>
#include <iostream>
#define NDEBUG
int factorial(int n) {
assert(n >= 0); // 確保 n 是非負數
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
int number = 5;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl;
number = -3;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl; // 這裡會觸發斷言
return 0;
}
輸出如下:
儘管定義了 NDEBUG 宏,但斷言 (assert) 仍然觸發錯誤輸出。
是不是很奇怪?
其實是個順序問題。
assert 宏的行為取決於 NDEBUG 宏是否在包含 <cassert>
之前被定義:
由於在包含 <cassert>
之後才定義 NDEBUG,前處理器在處理 #include <cassert>
時,NDEBUG 還未被定義,因此 assert 宏仍然處於啟用狀態。這導致即使在程式碼中定義了 NDEBUG,斷言依然會生效。
如何解決這個問題呢?
正確程式碼如下:
#define NDEBUG
#include <cassert>
#include <iostream>
int factorial(int n) {
assert(n >= 0); // 確保 n 是非負數
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
int number = 5;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl;
number = -3;
std::cout << "Factorial of " << number << " is " << factorial(number) << std::endl; // 這裡會觸發斷言
return 0;
}
輸出如下:
要將 #define NDEBUG 放在include <cassert>
之前
透過編譯器選項定義 NDEBUG:
比如:
g++ -DNDEBUG -o my_program my_program.cpp