C++中的assert

hisun9發表於2024-10-13

基本概念

在 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;
}

輸出如下:
img

在上述程式碼中,當 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;
}

輸出如下:
img

儘管定義了 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;
}

輸出如下:
img

要將 #define NDEBUG 放在include <cassert> 之前

透過編譯器選項定義 NDEBUG:

比如:

g++ -DNDEBUG -o my_program my_program.cpp

相關文章