本篇 ShengYu 來介紹 C++ static_assert 與 assert 的差異,assert 是 C/C++ 都有的巨集,static_assert 是 C++11 才新增的,
assert 的用法
assert 會在執行時間測試判斷陳述句,這邊來複習一下 assert 的用法,assert()
是如果它的條件陳述句回傳 false 的話會輸出錯誤訊息到 stderr 然後呼叫 abort 結束程式執行,
assert 最常是使用在檢查空指標 assert(p != NULL)
,
這邊我們示範是檢查 n 變數數值的大小,用來確保程式執行到這個時間點時數值應該是我們所預期的範圍,
C 要用 assert 需引用 <assert.h>
,C++ 要用 assert 請引用 <cassert>
,
要關閉 assert 的話,在引用 <cassert>
前定義 #define NDEBUG
,assert 就會被關閉,1
2
3
4
5
6
7
8
9
10// g++ cpp-assert.cpp -o a.out
int main() {
int n = 5;
assert(n > 10);
std::cout << n << "\n";
return 0;
}
執行時期的錯誤輸出如下,1
2cpp-assert: cpp-assert.cpp:9: int main(): Assertion `n > 10' failed.
Aborted (core dumped)
在 C++ 11 前靜態檢查的作法
這邊舉個最常會用到靜態檢查的例子,就是檢查 struct 的大小,就是我要確保程式在別的平台下 struct AAA 的大小也要是 8,但是用 assert 的話是執行到 assert 這一行才判斷的,如下,1
2
3
4
5
6
7
8
9
10
11
12
13
14// g++ cpp-assert2.cpp -o a.out
struct AAA {
int a; // 4 bytes
int b; // 4 bytes
}; // 8 bytes
int main() {
assert(sizeof(struct AAA) == 8);
std::cout << sizeof(struct AAA) << "\n";
return 0;
}
可是 struct 的大小這件事是在編譯時期就可以知道的事,為什麼不能在編譯時期檢查提早發現呢?
所以這邊利用了前置處理器的技巧來達成這件事,在 C++ 11 之前就會是這樣子寫,1
2
3
4
5
6
7
8
9
10
11
12
13
14// g++ cpp-assert3.cpp -o a.out
struct AAA {
int a; // 4 bytes
int b; // 4 bytes
}; // 8 bytes
int main() {
C_ASSERT(sizeof(struct AAA) == 8);
std::cout << sizeof(struct AAA) << "\n";
return 0;
}
看見上方的 #define C_ASSERT
的範例,我們可以瞭解在前置處理階段時先來判斷陳述句,
如果改成 C_ASSERT(sizeof(struct AAA) == 10)
的話,就會出現下面這樣的編譯錯誤訊息,1
2
3
4
5
6
7cpp-assert3.cpp: In function ‘int main()’:
cpp-assert3.cpp:3:55: error: size of array ‘__C_ASSERT__’ is negative
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
^
cpp-assert3.cpp:11:5: note: in expansion of macro ‘C_ASSERT’
C_ASSERT(sizeof(struct AAA) == 10);
^
這樣就達成了編譯時期的靜態檢查,除了上述的使用場合,也常使用來
- 檢查兩個 struct
C_ASSERT(sizeof(struct_a) == sizeof(struct_b))
- 檢查兩個 array
C_ASSERT(sizeof(arrar1) == sizeof(array2))
- 宣告的緩衝大小是否超過路徑的最大長度
C_ASSERT(buffer_size <= MAX_PATH)
等等這些情形。
C++11 把 static_assert 納入標準後,我們就不需要使用各平台或各函式庫各自實作的 static assert,使得更容易地跨平台開發。
C++ 11 static_assert 的用法
C++11 的 static_assert 宣告會在編譯時期測試判斷陳述句,
由於編譯器已知 struct AAA
結構的大小,因此會立即計算運算式的值。1
2
3
4
5
6
7
8
9
10
11
12
13// g++ cpp-static_assert.cpp -o a.out -std=c++11
struct AAA {
int a; // 4 bytes
int b; // 4 bytes
}; // 8 bytes
int main() {
static_assert(sizeof(struct AAA) == 8, "struct AAA size is not 8 bytes");
std::cout << sizeof(struct AAA) << "\n";
return 0;
}
執行結果為,1
8
如果把改成 sizeof(struct AAA) == 10
呢?編譯時期就會報錯,錯誤輸出如下,1
2
3
4cpp-static_assert.cpp: In function ‘int main()’:
cpp-static_assert.cpp:10:5: error: static assertion failed: struct AAA size is not 8 bytes
static_assert(sizeof(struct AAA) == 10, "struct AAA size is not 8 bytes");
^
總結
總結一下,static_assert 是 compile time 編譯時期來檢查陳述句 statement,而 assert 是 run time 執行時期來檢查陳述句 statement。
以上就是 C++ static_assert 與 assert 的差異介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!
其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例