1 定义

  1. #define likely(x) __builtin_expect(!!(x), 1)
  2. #define unlikely(x) __builtin_expect(!!(x), 0)

builtin_expect 是编译器内建函数,原型为 long builtin_expect (long exp, long c)。该函数并不会改变 exp 的值,但是可以对 if-else 分支或者 if 分支结构进行优化。
likely 代表 if 分支大概率会发生,
unlikely 代表 if 分支大概率不会发生。

Tips: !! 是 C 语言中处理逻辑表达式的一个技巧。因为 C 语言中没有布尔变量,所以布尔值是用整形来代替的,0 为假,非 0 为真。当 x 为 0 时,!(x) 为 1,!!(x) 为 0,!! 的运算没有什么意义;但当 x 为非 0 时(比如 100),!(x) 为 0,!!(x) 为 1,这样就达到了将非 0 值(比如 100)全部都映射为 1 的效果。

通过分析发现,unlikely 的定义其实是可以不使用!! 运算符的。

2 应用场景

总的来说,对代码运行效率有要求的 if-else 或 if 分支就应该使用 likely 或 unlikely 优化选项。

3 注意事项

  • likely 和 unlikely 的概率判断务必准确,不要写反了,否则非但不能提升运行效率,反而会起到反作用。
  • 选择表达式时要选择编译阶段编译器无法推测出真假的表达式,否则优化不起作用。
  • 编译时需要至少使用 - O2 选项,否则优化不起作用。

4 作用机理

4.1 理论

使用 likely 或 unlikely 为什么会起到提升代码运行效率的优化效果呢?

主要的作用机理有以下 2 点:

  • gcc 编译器在编译生成汇编代码时会在编译选项的引导下调整 if 分支内代码的位置,如果是 likely 修饰过的就调整到前面,如果是 unlikely 修饰过的就调整到后面。放到前面的代码可以节省跳转指令带来的时间开销,从而达到提升效率的目的。
  • 当代 CPU 都有 ICache 和流水线机制,在运行当前这条指令时,ICache 会预读取后面的指令,以提升运行效率。但是如果条件分支的结果是跳转到了其他指令,那预取的下一条指令(有的 CPU 设计是 4 级流水,也就是 4 条指令)就没用了,这样就降低了流水线的效率。如果使用 likely 和 unlikely 来指导编译器总是将大概率执行的代码放在靠前的位置,就可以大大提高预取值的命中率,从而达到提升效率的目的。


    https://blog.csdn.net/weixin_44873133/article/details/107302688