斷言語句是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
在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,第二個參數是可選的。
在上面介紹了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