C++的开源跨平台日志库glog学习研究(二)--宏的使用(二)

2014-11-24 12:24:38 · 作者: · 浏览: 2
开的,不再一一介绍了。
2. CHECK_XX宏
我个人感觉这类CHECK_XX宏比上面的LOG宏实现的还要隐晦难懂,当然设计的还是很巧妙的,值得学习一下,我尝试做个分析。
在测试工程的logging_unittest.cc文件line 535的TestCHECK()函数中有如下代码:
1 CHECK_NE(1, 2);
2 CHECK_GE(1, 1);
3 CHECK_GE(2, 1);
4 CHECK_LE(1, 1);
5 CHECK_LE(1, 2);
这些宏从名字上也能猜到是干嘛用的,他们的定义如下:
1 #define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
2 #define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
3 #define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
4 #define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
5 #define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
6 #define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
其中CHECK_OP宏定义如下:
#define CHECK_OP(name, op, val1, val2) \
CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
而CHECK_OP_LOG宏定义如下:
复制代码
1 typedef std::string _Check_string;
2 #define CHECK_OP_LOG(name, op, val1, val2, log) \
3 while (google::_Check_string* _result = \
4 google::Check##name##Impl( \
5 google::GetReferenceableva lue(val1), \
6 google::GetReferenceableva lue(val2), \
7 #val1 " " #op " " #val2)) \
8 log(__FILE__, __LINE__, \
9 google::CheckOpString(_result)).stream()
复制代码
接下来我们以CHECK_LE(1, 2);为例,将其逐步扩展:
复制代码
1 CHECK_LE(1, 2)
2 ------> CHECK_OP(_LE, <=, 1, 2)
3 ------> CHECK_OP_LOG(_LE, <=, 1, 2, google::LogMessageFatal)
4 ------> #define CHECK_OP_LOG(_LE, <=, 1, 2, google::LogMessageFatal) \
5 while (std::string * _result = \
6 google::Check_LEImpl( \
7 1, \
8 2, \
9 "1 <= 2")) \
10 log(__FILE__, __LINE__, \
11 google::CheckOpString(_result)).stream()
复制代码
其中google::Check_LEImpl也是通过宏预先实现的,这个宏就是DEFINE_CHECK_OP_IMPL(Check_LE, <=):
复制代码
1 #define DEFINE_CHECK_OP_IMPL(name, op) \
2 template \
3 inline std::string* name##Impl(const T1& v1, const T2& v2, \
4 const char* exprtext) { \
5 if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
6 else return MakeCheckOpString(v1, v2, exprtext); \
7 } \
8 inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
9 return name##Impl(v1, v2, exprtext); \
10 }
复制代码
展开后就实现了google::Check_LEImpl函数(其他与此类似,这里只以“<=”为例说明):
CHECK_LE(1, 2) ------>
while (std::string * _result = google::Check_LEImpl(1, 2, "1 <= 2"))
log(__FILE__, __LINE__,google::CheckOpString(_result)).stream()
其中google::Check_LEImpl又调用了模板实现的Check_LEImpl,该函数根据两个参数v1、v2和操作符op决定了要么返回NULL,要么返回一个string*,如果返回NULL,则不再执行下面的输出,否则则输出日志信息。
其中宏GOOGLE_PREDICT_TRUE、内联函数GetReferenceableva lue、函数MakeCheckOpString、函数CheckOpString、结构体CheckOpString都是比较简单的,就不再讲了。
至此,就完成了CHECK_LE(1, 2)的扩展,如果检测为true,则返回NULL,否则就会返回一个有明确提示信息的字符串指针,并输出该信息,然后是程序宕掉。
比如如果验证CHECK_LE(1, 0),因为为false,则触发日志输出:
F0503 17:39:09.961318 4232 logging_unittest.cc:203] Check failed: 1 <= 0 (1 vs. 0)
*** Check failure stack trace: ***
然后程序异常退出。
3. 在宏中使用do-while(0)
比如在logging.h的817行有如下宏定义:
1 #define CHECK_DOUBLE_EQ(val1, val2) \
2 do { \
3 CHECK_LE((val1), (val2)+0.000000000000001L); \
4 CHECK_GE((val1), (val2)-0.000000000000001L); \
5 } while (0)
这里主要关注do-while(0)的使用,恰巧我之前也写过一篇文章介绍do-while(0)的妙用,请看:do{...}while(0)的妙用,这里不再多言了。
4. 使用宏进行全局初始化
请看下面的宏用法:
REGISTER_MODULE_INITIALIZER(utilities, yUserNameInitializer());
REGISTER_MODULE_INITIALIZER在googleinit.h的44行定义:
1 #define REGISTER_MODULE_INITIALIZER(name, body) \
2 namespace { \
3 static void google_init_module_##name () { body; } \
4 GoogleInitializer google_initializer_module_##name(#name, \
5 google_init_module_##name); \
6 }
其中类GoogleInitializer的实现如下:
复制代码
1 class GoogleInitializer {
2 public:
3 typedef void (*void_function)(void);
4 GoogleInitializer(const char*, void_function f) {
5 f();
6 }
7 };
复制代码
这个比较简单,其实就是做一些比如注册、全局初始化的工作,相应的也可以设置对应的宏用于做程序退出时的清理工作。