C++ 斷言


assert宏 (基本概念與用法整理)

assert宏的深入學習

1、運行時斷言

1.1、assert屬於運行時斷言,可以在運行時判斷給定條件是否為真,如果為真則什么也不做,否則打印一跳錯誤信息,然后通過abort來終止程。當程序開發階段,我們可以在debug模式下加入大量的運行時斷言,來提高我們程序的健壯性,並且提高開發速度。但是當程序需要發布的時候,大量的斷言會影響程序的運行效率,此時我們只需要在assert.h頭文件前加#define NDEBUG.

1.2、斷言有一個問題,就是一定會abort,強制整個程序退出而導致調試也無法繼續進行,就像上圖這樣,出現問題后,我們知道了出現問題的行號,但是我們需要手動在該行的上面設置斷點,重新開始調試才能夠檢查到發生問題時各個變量的狀態。而且,有時問題不是那么容易重現,於是就可能出現沒法重現錯誤再檢查狀態的問題。

  所以,我們可以自己寫一個類似的宏來解決這個問題,我們希望在違反斷言時觸發斷點陷阱門中斷而不是調用abort,這樣,在違反斷言時程序會暫停下來,等待程序員來檢查當前的狀態有何異常

#define _ASSERT(x) if (!(x)) __asm {int 3}; //是檢查斷言,然后如果斷言結果為false(0),那么就調用內聯匯編指令int 3陷入調試中斷

1.3、用戶自定義斷言

實現功能:斷言的時候可以支持變量輸出SMART_ASSERTvalue && "Invalid value!")("1")(s);

//頭文件

////////////////////////////////////////////////////////////////////////////////

#include

#include

#include

#include

class Assert

{

public:

//編譯期,SMART_ASSERT宏被替換,斷言被命中時

//1、如果斷言后跟有括號括起來的參數時

//SMART_ASSERT_C和SMART_ASSERT_N將不會被認為是成員,而是SMART_ASSERT_C(x)和SMART_ASSERT_N(x)宏

//間接替換為調用ShowMemoryValue成員方法。

//2、如果斷言命中時后邊無括號,則SMART_ASSERT_C被認為是成員變量;

//如果斷言命中時后邊括號在多次宏替換之后沒有啦,則SMART_ASSERT_OP宏被替換后的最后一個.調用被認為是成員變量調用

Assert & SMART_ASSERT_C;

Assert & SMART_ASSERT_N;//SMART_ASSERT_C和SMART_ASSERT_N循環調用,來解析斷言后邊追加的參數

Assert( const wchar_t *wexpr

, const wchar_t *wfile

, const char * expr

, const char * file

, unsigned line)

: _Expr(wexpr)

, _File(wfile)

, _Line(line)

, _CFile(file)

, _Message(expr)

, SMART_ASSERT_C(*this)

, SMART_ASSERT_N(*this)

{

};

~Assert();

//如果需要支持打印多種數據類型,可以對該方法的第二個參數重載,或者對SMART_ASSERT_OP宏的進行修改,傳入參數x時強制轉換

為string類型

Assert & RestoreMemoryValue(const char * key, const std::string &val);

private:

std::wstring _Expr;//異常表達式

std::wstring _File;//文件名稱

unsigned _Line;//文件行數

std::string_CFile;//文件名稱

std::string_Message;//異常消息

std::map _memoryValue;//內存變量值

};

#ifdef SMART_ASSERT

#undef SMART_ASSERT

#endif

#define SMART_ASSERT_C(x)SMART_ASSERT_OP(x, N)

#define SMART_ASSERT_N(x)SMART_ASSERT_OP(x, C)

#define SMART_ASSERT_OP(x, next) \

SMART_ASSERT_C.RestoreMemoryValue(#x, (x)).SMART_ASSERT_##next

#define SMART_ASSERT(expr) \

if ( (expr) ); \

else Assert(_CRT_WIDE(#expr), _CRT_WIDE(__FILE__), #expr, __FILE__, __LINE__).SMART_ASSERT_C

//實現

////////////////////////////////////////////////////////////////////

#include

#include "SmartAssert.h"

//https://msdn.microsoft.com/zh-cn/library/9sb57dw4.aspx  :_wassert說明

Assert::~Assert()

{

//獲取_memoryValue臨時變量值打印

//進入中斷

_wassert(_Expr.c_str(), _File.c_str(), _Line);

}

Assert & Assert::RestoreMemoryValue(const char *key, const std::string &val)

{

_memoryValue[key] = val;

return *this;

};

2、靜態斷言

    在2011年的C++標准中出現了靜態斷言(static_assert)的語法,所謂靜態斷言,就是在編譯時就能夠進行檢查的斷言,static_assert

是C++的標准語法,不需要引用頭文件。靜態斷言的另一個好處是,可以自定義違反斷言時的編譯錯誤信息。

例如:

const int i = 22;

static_assert(i != 22, "i equals to 22");//這個代碼,將無法通過編譯,因為i的值違反了靜態斷言。

注意:靜態斷言的限制是,斷言本身必須是常量表達式,如果這樣的i不是常量,靜態斷言是不符合語法的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM