在PHP扩展开发中,经常会看到EXPECTED
与UNEXPECTED
两个宏的使用,但是却不清楚它们的用途,这次就来拨开它们的面纱。
首先举个在PHP底层中使用到EXPECTED
与UNEXPECTED
的例子:
if (UNEXPECTED(_num_args < _min_num_args) || \
(UNEXPECTED(_num_args > _max_num_args) && \
EXPECTED(_max_num_args >= 0))) { \
if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
if (_flags & ZEND_PARSE_PARAMS_THROW) { \
zend_wrong_parameters_count_exception(_min_num_args, _max_num_args); \
} else { \
zend_wrong_parameters_count_error(_min_num_args, _max_num_args); \
} \
} \
error_code = ZPP_ERROR_FAILURE; \
break; \
} \
这是Zend提供用于解析函数参数的一个宏的部分代码,大致代码逻辑就是判断参数数量是否不正确。在zend_API.h
中,EXPECTED
和UNEXPECTED
是这样定义的:
#if PHP_HAVE_BUILTIN_EXPECT
# define EXPECTED(condition) __builtin_expect(!!(condition), 1)
# define UNEXPECTED(condition) __builtin_expect(!!(condition), 0)
#else
# define EXPECTED(condition) (condition)
# define UNEXPECTED(condition) (condition)
#endif
可以发现它们其实是对__builtin_expect
函数的一个封装,所以最终就是要搞清楚__builtin_expect
到底是干嘛的。
__builtin_expect()是GCC v2.96版本引入的内建函数,提供给程序员做分支预测。
简单来说,就是程序员告诉编译器,后续的条件判断中可能性最大的条件分支是什么,方便编译器针对代码进行优化,将可能性最大的分支代码放在前面,降低指令跳转的可能性,以优化性能。例如:
// 假如有a变量
if (EXPECTED(a == 0)) {
// ...
} else {
// ...
}
以上代码表示,a == 0的可能性更大,即更有可能执行if分支代码,此时,编译器就会将if分支代码放在前面。反之,如果使用UNEXPECTED
,就会将else分支代码放在前面。