C++中#error/assert/static_assert的区别及使用
C++ 語言支持可幫助您調(diào)試應(yīng)用程序的三個(gè)錯(cuò)誤處理機(jī)制:#error 指令、static_assert 關(guān)鍵字和 assert (CRT) 宏。所有的三種機(jī)制都會(huì)發(fā)出錯(cuò)誤消息。
#error可看做預(yù)編譯期斷言,甚至都算不上斷言,僅僅能在預(yù)編譯時(shí)顯示一個(gè)錯(cuò)誤信息,它能做的不多,可以參與預(yù)編譯的條件檢查,由于它無法獲得編譯信息,當(dāng)然就做不了更進(jìn)一步分析了。使用#error方法是非常煩瑣的,并且不能夠?qū)δ0鍏?shù)進(jìn)行檢查,因?yàn)槟0鍖?shí)例化是在編譯時(shí)進(jìn)行,而#error方法是在預(yù)處理階段進(jìn)行的。
#error 指令在預(yù)處理時(shí)有效。它將無條件地發(fā)出用戶指定的消息并導(dǎo)致編譯因錯(cuò)誤而失敗。該消息可包含由預(yù)處理器指令操作的文本,但不會(huì)計(jì)算任何生成的表達(dá)式。
assert是運(yùn)行期斷言,它用來發(fā)現(xiàn)運(yùn)行期間的錯(cuò)誤,不能提前到編譯期發(fā)現(xiàn)錯(cuò)誤,也不具有強(qiáng)制性,也談不上改善編譯信息的可讀性,既然是運(yùn)行期檢查,對(duì)性能當(dāng)然是有影響的,所以經(jīng)常在發(fā)行版本中,assert都會(huì)被關(guān)掉。
assert (CRT) 宏在運(yùn)行時(shí)有效。它會(huì)計(jì)算用戶指定的表達(dá)式,如果結(jié)果為零,系統(tǒng)將發(fā)出診斷消息并關(guān)閉應(yīng)用程序。
static_assert語法:static_assert(constant-expression,string-literal);
static assert is used to make assertions at compile time. When the static assertion fails, the program simply doesn't compile.
static_assert這個(gè)宏用于檢測(cè)和診斷編譯時(shí)錯(cuò)誤。編譯期,這是一個(gè)與 CRT-assert(運(yùn)行時(shí)宏)相反的宏。這個(gè)宏用于檢測(cè)編譯時(shí)程序的不變量。static_asset 是在編譯時(shí)執(zhí)行的,不能用于檢測(cè)運(yùn)行時(shí)的值。而斷言assert宏只有在程序運(yùn)行時(shí)才能起作用。
static_assert宏,在編譯時(shí)測(cè)試軟件斷言。如果指定的常量表達(dá)式為false,則編譯器顯示指定的消息,并且編譯失敗,錯(cuò)誤為 C2338;否則,聲明不起作用。
static_assert 聲明的constant-expression 參數(shù)表示軟件斷言。軟件斷言指定在程序的某個(gè)特定點(diǎn)應(yīng)滿足的條件。如果滿足該條件,則 static_assert 聲明無效。如果未滿足該條件,則斷言失敗,編譯器在 string-literal 參數(shù)中顯示消息,并且編譯因出錯(cuò)而失敗。
static_assert 聲明在編譯時(shí)測(cè)試軟件斷言。相反,assert (CRT) 宏在運(yùn)行時(shí)測(cè)試軟件斷言,并會(huì)導(dǎo)致增大運(yùn)行時(shí)花費(fèi)的空間和時(shí)間。由于模板參數(shù)包含在constant-expression 參數(shù)中,因此 static_assert 聲明對(duì)于調(diào)試模板很有用。
當(dāng)遇到聲明時(shí),編譯器將檢查static_assert 聲明是否存在語法錯(cuò)誤。如果編譯器不依賴于模板參數(shù),則編譯器會(huì)立即計(jì)算 constant-expression 參數(shù)。否則,在對(duì)模板進(jìn)行實(shí)例化時(shí),編譯器將計(jì)算 constant-expression 參數(shù)。因此,當(dāng)遇到聲明時(shí),編譯器可能一次發(fā)布一個(gè)診斷消息,而在對(duì)模板進(jìn)行實(shí)例化時(shí)也是如此。
可以在命名空間、類或塊范圍中使用static_assert 關(guān)鍵字。(由于 static_assert 關(guān)鍵字可以在命名空間范圍內(nèi)使用,因此,即使它不將新名稱引入程序中,但從技術(shù)上講,它也是一個(gè)聲明。)
使用static_assert,我們可以在編譯期間發(fā)現(xiàn)更多的錯(cuò)誤,用編譯器來強(qiáng)制保證一些契約,并幫助我們改善編譯信息的可讀性,尤其是用于模板的時(shí)候。static_assert可以用在全局作用域中,命名空間中,類作用域中,函數(shù)作用域中,幾乎可以不受限制的使用。編譯器在遇到一個(gè)static_assert語句時(shí),通常立刻將其第一個(gè)參數(shù)作為常量表達(dá)式進(jìn)行演算,但如果該常量表達(dá)式依賴于某些模板參數(shù),則延遲到模板實(shí)例化時(shí)再進(jìn)行演算,這就讓檢查模板參數(shù)成為了可能。
由于static_assert是編譯期間斷言,不生成目標(biāo)代碼,因此static_assert不會(huì)造成任何運(yùn)行期性能損失。
static_assert聲明在編譯時(shí)有效。它將測(cè)試由用戶指定且可以轉(zhuǎn)換為布爾值的整數(shù)表達(dá)式表示的軟件斷言。如果表達(dá)式的計(jì)算結(jié)果為零 (false),編譯器將發(fā)出用戶指定的消息,并且編譯因錯(cuò)誤而失敗。static_assert 聲明對(duì)調(diào)試模板尤其有用,因?yàn)槟0鍏?shù)可包含在用戶指定的表達(dá)式中。
以下是測(cè)試代碼:
static_assert.hpp:
#ifndef FBC_MESSY_TEST_STATIC_ASSERT_HPP
#define FBC_MESSY_TEST_STATIC_ASSERT_HPP#ifndef __cplusplus#error static_assert.hpp header must be compiled as C++
#endif#include <type_traits>
#include <iosfwd>
#include <cassert>// reference: https://msdn.microsoft.com/zh-cn/library/dd293588.aspx// static_assert 聲明具有類范圍。 static_assert 驗(yàn)證模板參數(shù)是否為純舊數(shù)據(jù) (POD) 類型。
// 編譯器將在聲明 static_assert 聲明時(shí)檢查該聲明,但不計(jì)算 constant-expression 參數(shù),直到在 main() 中實(shí)例化 basic_string 類模板
template <class CharT, class Traits = std::char_traits<CharT> >
class basic_string {static_assert(std::tr1::is_pod<CharT>::value, "Template argument CharT must be a POD type in class template basic_string");// ...
};struct NonPOD {NonPOD(const NonPOD &) {}virtual ~NonPOD() {}
};// reference: http://stackoverflow.com/questions/1647895/what-does-static-assert-do-and-what-would-you-use-it-for
class Foo
{
public:static const int bar = 5; // 3
};static_assert(Foo::bar > 4, "Foo::bar is too small :(");void test_static_assert1();
void test_static_assert2();
void test_static_assert3();
void test_static_assert4(int a);#endif // FBC_MESSY_TEST_STATIC_ASSERT_HPP#include "static_assert.hpp"void test_static_assert1()
{// static_assert 聲明具有命名空間范圍。由于編譯器知道類型 void * 的大小,因此可以立即計(jì)算表達(dá)式//該static_assert用來確保編譯僅在32位的平臺(tái)上進(jìn)行,不支持64位的平臺(tái)//static_assert(sizeof(void *) == 4, "64-bit code generation is not supported."); // sizeof(void *) = 8 ?
}void test_static_assert2()
{basic_string<char> bs;
}void test_static_assert3()
{Foo::bar;
}void test_static_assert4(int a)
{assert(a / 2 == 0);
}主要參考文獻(xiàn):
1.?https://msdn.microsoft.com/zh-cn/library/dd293588.aspx
 GitHub:https://github.com/fengbingchun/Messy_Test
總結(jié)
以上是生活随笔為你收集整理的C++中#error/assert/static_assert的区别及使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: C++中的explicit关键字介绍
- 下一篇: C/C++中inline/static
