likely 和 unlikely 是 c++++ 中用于优化分支预测的编译器扩展宏,1. likely(x) 表示条件 x 更可能为真,2. unlikely(x) 表示 x 更可能为假,它们通过 \_\_builtin\_expect 告知编译器热路径以减少跳转开销;常见于错误处理、低概率事件、热点代码中,但应结合性能分析谨慎使用,避免误导编译器或降低可读性,在 c++20 中可用 [[likely]] 和 [[unlikely]] 替代。

在 C++ 编程中,分支预测失败(Branch Misprediction)是影响程序性能的一个常见问题。现代 CPU 通过预测分支走向来提前执行指令流水线,但如果预测错误,会导致流水线清空、重新加载,带来不小的性能损失。为了帮助编译器更好地进行优化,C++ 提供了 __builtin_expect 这类机制,配合宏定义 likely 和 unlikely,可以显式告诉编译器某个条件更可能为真还是假。

什么是 likely 和 unlikely?
likely(x) 表示表达式 x 很可能会成立,而 unlikely(x) 表示 x 很可能不成立。它们并不是语言标准的一部分,而是 GCC、Clang 等编译器提供的扩展功能。

实际使用时通常会这样定义宏:
立即学习“C++免费学习笔记(深入)”;
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
这样做的目的是让编译器将更可能执行的代码块放在顺序执行路径上,从而减少跳转带来的开销。

在哪些场景下值得使用?
-
错误处理或异常路径:例如检查函数参数是否为空指针,这种情况通常是“正常”路径之外的异常情况。
if (unlikely(ptr == nullptr)) { // 错误处理逻辑 } 事件发生概率极低的情况:比如日志记录中的调试级别判断,如果默认关闭,可以用
unlikely标记。热点代码中的关键判断:如果你已经通过 profiling 发现某个条件分支经常走某一侧,可以考虑用提示优化。
不过要注意,并不是所有地方都适合加这些提示。滥用反而可能导致代码可读性下降,甚至误导编译器。
使用时需要注意的细节
不要过度依赖:CPU 的分支预测硬件已经非常强大,多数情况下不需要手动干预。只有在性能敏感区域才需要考虑。
和 profiling 结合使用更好:可以通过 perf 工具等分析出真正的热路径,再决定是否加 likely/unlikely。
-
不同编译器支持略有差异:GCC 和 Clang 支持
__builtin_expect,MSVC 则没有直接对应的功能,可以考虑用[[likely]]和[[unlikely]](C++20 起支持)代替。示例:
if (condition) [[likely]] { // 更可能执行的分支 } else [[unlikely]] { // 不太可能执行的分支 }
总结一下
合理使用 likely 和 unlikely 可以辅助编译器生成更高效的机器码,尤其是在分支预测容易失败的关键路径上。但要记住:
- 它们只是建议,不是强制;
- 需要结合性能分析结果;
- 不要到处乱用,保持代码简洁清晰更重要。
基本上就这些,理解原理后在合适的地方加上一两个提示,有时能带来意想不到的性能提升。










