C98或C99中的库为:<cassert> 或<assert.h>
运行时断言,故明思议是当程序在运行的时候才作为判决,可以认为是对参数的有效性的判断。
而静态断言,是对参数的条件判断提前做了,在预编译的时候进行完成的。如:
//demo1.cpp #include <cassert> using namespace std; char *arrayAolloc(int n){ assert(n>0); return new char [n]; } int main(){ char * a = arrayAolloc(0); return 0; } //gcc demo1.cpp -omain
assert(n>0); 该条件只会在当arrayAlloc的时候才会进行判断,要根据程序的传参来处理其有效性。
如下:
template <typename T, typename U> int bit_copy(T& a, U& b){ assert(sizeof(b) == sizeof(a)); memcpy(&a, &b, sizeof(b)); };
上述很明显示,T与U并非是同一个类型,但是assert同样不参在编译的时候检查出来,只有当程序运行后才可以判断到。
下面作一个改进,定义一个宏:
#define assert_static(e) do { enum { assert_static__ = 1/(e)}; } while (0) template <typename T, typename U> int bit_copy(T& a, U& b){ assert_static(sizeof(b) == sizeof(a)); memcpy(&a, &b, sizeof(b)); };
这样我们在编译时宏替换的过程中,就可以检查到,1/0是一个错误的语法,就直接抛出来了。
在C11中,库函数中已经存在了这样的函数 static_assert(expr, desc);
如果在编译的时候expr==false, 那么将会抛出desc的信息,这样就可以直接从代码中排查出硬性的错误,不必等到程序运行后,才检查出来。
static_assert是编译时的断言,其使用范围不像assert一样受到限制。
static_assert的断言参数expr必须是已知的常量,该常量在编译时就可以判断出来。
无法在编译时判断的常量,不可用static_assert来断言,如下:
template <typename T, typename U> int bit_copy(T& a, U& b){ //assert_static(sizeof(b) == sizeof(a)); static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have the same width."); memcpy(&a, &b, sizeof(b)); }; int positive(const int n){ static_assert(n > 0, "abcd:"); } $ g++ -std=c++11 -c 2.2.8.cpp 2.2.8.cpp: 在函数‘int positive(int)’中: 2.2.8.cpp:20:2: 错误:静态断言中出现非常量条件 static_assert(n > 0, "abcd:"); ^ 2.2.8.cpp:20:2: 错误:‘n’不是一个常量表达式 2.2.8.cpp: In instantiation of ‘int bit_copy(T&, U&) [with T = int; U = double]’: 2.2.8.cpp:25:15: required from here 2.2.8.cpp:15:2: 错误:static assertion failed: the parameters of bit_copy must have the same width. static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have the same width.");