【C++】C++中assert和ENDEGU預處理語句

assert

斷言語句是C++中的一種預處理宏語句,它能在程序運行時根據否認條件中斷程序。

C++中的assert()函數能夠實現斷言功能,在使用assert函數以前應該先引入<cassert>頭文件。
函數:c++

void assert (int expression);

若是參數表達式不爲0(也就是true),那麼什麼都不會發生。參數表達式爲0(也就是false),那麼將會有一條標準的錯誤消息被打印,隨後調用abort中斷運行程序。

打印的錯誤消息內容依據不一樣的實現庫會有不一樣的消息內容。但消息內容至少應該包括:斷言失敗的表達式,文件的名稱,斷言失敗處在文件中的行數。

好比:express

#include <array> /*array*/
#include <assert> /*assert()*/
using namespace std;
int getArrayValue(const std::array<int, 10> &array, int index)
{
    // 斷言index的範圍是[0,9]
    assert(index >= 0 && index <= 9); // 這個是test.cpp的第7行
    return array[index];
}
int main(int argc,char **argv){
  array<int,10> array = {1,2,3,4,5,6,7,8,9,10};
  getArrayValue(array,-3);//調用getArrayValue函數,傳入一個錯誤的index值
return 0;
}

會獲得以下的報錯信息:數組

test.cpp:7: int getArrayValue(std::array<int, 10ul>, int): Assertion `index >=0 && index <=9' failed.

 

如何給斷言語句添加額外的描述信息
有時斷言語句的描述信息不夠清晰,好比考慮以下這種狀況:函數

assert(found);

若是這個斷言被觸發,那麼會獲得相似於以下的錯誤信息:spa

file_name:line_number : function_name: Assertion 'found' failed.

這種狀況,若是隻看斷言輸出是得不到詳細的信息,必須要去查看代碼才能肯定是什麼緣由致使了錯誤。

那麼有沒有什麼方式能夠爲斷言添加一些額外的描述信息呢?答案是有的。咱們能夠利用C++中的&&符,添加一個字符串字面值的描述信息。調試

assert(found && "Car could not found in database"); 

因爲字符串字面值老是爲true,因此整個表達式的真假性仍是取決於found變量。這樣的話,既添加了額外的描述信息,又不改變原來的含義。
若是斷言觸發,會獲得以下的結果:c++11

file_name:line_number : function_name: Assertion 'found && "Car could not found in database"' failed.

從斷言輸出的錯誤信息中,能夠看到詳細的錯誤描述。code

 

static_assert

在c++11標準中添加了一種靜態斷言static_assert,和assert不一樣的是:assert表達式的檢查在運行時發生,static_assert的檢查在編譯時發生。

若是static_assert斷言被觸發的話,那麼會在控制檯打印錯誤信息,同時編譯失敗。若static_assert斷言未被觸發,那麼編譯順利經過。
好比:blog

static_assert(sizeof(long) == 8, "long must be 8 bytes");
int main(){return 0;}

若是編譯機器long類型不佔8個字節的話,那麼在編譯的時候就會出現以下的錯誤信息:字符串

static assertion failed: long must be 8 bytes


由於static_assert對條件式的檢查發生在編譯時,因此條件表達式必定要能在編譯時被計算出來。在c++11中,static_assert的第二個參數是必需提供的,到c++17,第二個參數是可選的。

 

EDEBUG

在上面介紹了assert斷言語句,其實assert的行爲依賴一個名爲NDEBUG的預處理變量的狀態,若是定義了ENDEBUG,則assert什麼也不會發生。默認狀態下沒有定義NDEBUG,assert會執行運行時檢查。
例如:

#define NDEBUG
#include <assert> /*assert()*/
int getArrayValue(const std::array<int, 10> &array, int index)
{
    // 斷言index的範圍是[0,9]
    assert(index >= 0 && index <= 9); // 這個是test.cpp的第7行
    return array[index];
}

注意#define NDEBUG必需要寫在#include <assert>語句以前。

定義NDEBUG能避免檢查各類條件所需的運行時開銷,固然此時根本就不會執行運行時檢查。除了使用assert外,也能夠使用NDEBUG編寫本身的條件調試代碼。若是NDEBUG未定義,將執行#ifndef和#endif之間的代碼;若是定義了NDEBUG,這些代碼將會被忽略掉:

void print(const int ia[],size_t size){
#ifndef NDEBUG
    cerr << __func__ << ": array size is" << size << endl;
#endif
//...
}

上面這段代碼中,咱們使用變量__func__輸出當前調試函數的名字。編譯器爲每一個函數都定義了__func__,它是const char的靜態數組,用於存放函數的名稱。

C++編譯器除了定義過__func__,預處理器還定義了一些調試很是有用的名字。
__FILE__ 存放文件名的字符串字面值
__LINE__ 存放當前行號的整形字面值
__TIME__ 存放文件編譯時間的字符串字面值
__DATE__ 存放文件編譯日期的字符串字面值

能夠使用這些變量在錯誤消息中提供更多信息,例如:

if(word.size() < minLen)
cerr     << "Error : " << __FILE__
    << " : In function " << __func__
    << " at Line " << __LINE__ << endl
    << "    Compiled on " << __DATE__
    << " at time " << __TIME__ << endl
    << "    Word read was \"" << word
    << "\" : Length too short" << endl;

若是提供一個小於minLen的變量,那麼會獲得相似以下的錯誤信息:

Error : test.cpp : In function main at line 27
    Compiled on Jul 11 2019 at 20:00:00
    Word read was "foo" : Length too short
相關文章
相關標籤/搜索