写读Blob源码的时候,读完blob.hpp后,发现其中存在如下的这些方法。下面我们详细的来分析这些方法的源码以及它们的函数功能。
- CHECK_EQ()
- CHECK_LE()
- CHECK_GE()
- CHECK_LT()
CHECK方法是封装在GLOG库中,而GLOG库是Google开发的用于记录应用程序的使用库,提供基于C++标准输入输出流形式的接口,记录时可以选择不同的日志级别,方便将重要日志和普通日志分开。 GLOG 提供如下的CHECK方法:
代码位于 /usr/include/glog/logging.h
// Equality/Inequality checks - compare two values, and log a FATAL message
// including the two values when the result is not as expected. The values
// must have operator<<(ostream, ...) defined.
//
// You may append to the error message like so:
// CHECK_NE(1, 2) << ": The world must be ending!";
//
// We are very careful to ensure that each argument is evaluated exactly
// once, and that anything which is legal to pass as a function argument is
// legal here. In particular, the arguments may be temporary expressions
// which will end up being destroyed at the end of the apparent statement,
// for example:
// CHECK_EQ(string("abc")[1], 'b');
//
// WARNING: These don't compile correctly if one of the arguments is a pointer
// and the other is NULL. To work around this, simply static_cast NULL to the
// type of the desired pointer.
#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) #相当于assert(val1 == val2)
# release下可用,如果检测为true,则返回NULL,否则返回一个有明确提示信息的字符串指针,并输出改信息,然后程序宕机
#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) #相当于assert(val1 != val2)
#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) #相当于assert(val1 <= val2)
#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) #相当于assert(val1 < val2)
#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) #相当于assert(val1 >= val2)
#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) #相当于assert(val1 > val2)
到此,我们已经搞清楚CEHCK函数具有什么功能,我们接着去看,现在我们来查看CHECK_OP 源码部分,宏定义的代码如下:
代码位于 /usr/include/glog/logging.h
#if GOOGLE_STRIP_LOG <= 3
#define CHECK_OP(name, op, val1, val2) \
CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
#else
#define CHECK_OP(name, op, val1, val2) \
CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
#endif // STRIP_LOG <= 3
GOOGLE_STRIP_LOG是限制等级,低于这个等级的都不会被显示。
下面,我们查看CHECK_OP_LOG()部分源码
#if defined(STATIC_ANALYSIS)
// Only for static analysis tool to know that it is equivalent to assert
#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
#elif !defined(NDEBUG)
// In debug mode, avoid constructing CheckOpStrings if possible,
// to reduce the overhead of CHECK statments by 2x.
// Real DCHECK-heavy tests have seen 1.5x speedups.
// The meaning of "string" might be different between now and
// when this macro gets invoked (e.g., if someone is experimenting
// with other string implementations that get defined after this
// file is included). Save the current meaning now and use it
// in the macro.
typedef std::string _Check_string;
#define CHECK_OP_LOG(name, op, val1, val2, log) \
while (google::_Check_string* _result = \
google::Check##name##Impl( \
google::GetReferenceableValue(val1), \
google::GetReferenceableValue(val2), \
#val1 " " #op " " #val2)) \
log(__FILE__, __LINE__, \
google::CheckOpString(_result)).stream()
#else
// In optimized mode, use CheckOpString to hint to compiler that
// the while condition is unlikely.
#define CHECK_OP_LOG(name, op, val1, val2, log) \
while (google::CheckOpString _result = \
google::Check##name##Impl( \
google::GetReferenceableValue(val1), \
google::GetReferenceableValue(val2), \
#val1 " " #op " " #val2)) \
log(__FILE__, __LINE__, _result).stream()
#endif // STATIC_ANALYSIS, !NDEBUG
这里我们举个例子,以 CHECK_EQ(1,2) 为例,来看其执行过程。
CHECK_EQ(1,2) ---> CHECK_OP(_NE, ==, 1, 2) --->
CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal) --->
#define CHECK_OP_LOG(_NE, ==, 1, 2, google::LogMessageFatal) \
while (google::_Check_string* _result = \
google::Check_EQ_Impl( \
google::GetReferenceableValue(1), \
google::GetReferenceableValue(2), \
"1== 2")) \
log(__FILE__, __LINE__, \
google::CheckOpString(_result)).stream()
其中 google::Check_EQ_Impl() 也是通过宏预先定义的,这个宏的定义如下:
// Helper functions for CHECK_OP macro.
// The (int, int) specialization works around the issue that the compiler
// will not instantiate the template version of the function on values of
// unnamed enum type - see comment below.
#define DEFINE_CHECK_OP_IMPL(name, op) \
template <typename T1, typename T2> \
inline std::string* name##Impl(const T1& v1, const T2& v2, \
const char* exprtext) { \
if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
else return MakeCheckOpString(v1, v2, exprtext); \
} \
inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
return name##Impl<int, int>(v1, v2, exprtext); \
}
// We use the full name Check_EQ, Check_NE, etc. in case the file including
// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
// This happens if, for example, those are used as token names in a
// yacc grammar.
DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)?
DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead.
DEFINE_CHECK_OP_IMPL(Check_LE, <=)
DEFINE_CHECK_OP_IMPL(Check_LT, <)
DEFINE_CHECK_OP_IMPL(Check_GE, >=)
DEFINE_CHECK_OP_IMPL(Check_GT, > )
#undef DEFINE_CHECK_OP_IMPL
最后我们可以发现CHECK_EQ(1,2) 真正的执行过程是
CHECK_EQ(1, 2) ------->
while (google::_Check_string* _result = \
google::Check_EQ_Impl( \
google::GetReferenceableValue(1), \
google::GetReferenceableValue(2), \
"1== 2")) \
log(__FILE__, __LINE__, \
google::CheckOpString(_result)).stream()