应优先使用 std::midpoint 防整数溢出,但仅适用于同类型整型或指针中点计算;浮点场景无效,需注意 c++20 标准、 头文件及编译器版本支持。

能用 std::midpoint 就别手写 (a + b) / 2——它专为防整数溢出而生,但不是所有场景都适用,尤其不能当通用“平均值函数”乱用。
std::midpoint 编译不过?先确认 C++20 和头文件
它定义在 <numeric></numeric>,不是 <cmath></cmath> 或 <algorithm></algorithm>。MSVC 2019 默认不启用 C++20,GCC/Clang 必须加 -std=c++20(或更高)。否则报错:'midpoint' is not a member of 'std'。
- 检查编译器版本:MSVC ≥ 19.28(即 VS 2019 v16.8+),GCC ≥ 10,Clang ≥ 11 才完整支持
- 不要依赖 IDE 默认标准;CMake 中需显式设置
set(CMAKE_CXX_STANDARD 20) - 头文件漏掉
#include <numeric></numeric>是最常见低级错误
整数中点 ≠ 数学平均值:向下取整语义必须清楚
std::midpoint(a, b) 对整型返回的是 ⌊(a+b)/2⌋(向负无穷取整),不是四舍五入,也不是截断除法。它等价于 a + (b - a) / 2,但全程不触发加法溢出。
-
std::midpoint(-3, 2)返回-1(不是 0) -
std::midpoint(0, 1)返回0(不是 0.5) - 类型严格匹配:不能传
std::midpoint(10U, 20)(unsigned intvsint),编译失败 - 结果类型与参数完全一致,不发生隐式提升(
short输入 →short输出)
浮点数调用 std::midpoint?没意义,还可能更差
C++20 确实提供了 std::midpoint(float, float) 重载,但它只是语法存在,底层仍走 (a + b) / 2,不规避浮点溢出或精度坍塌。
- 当
a = 1e30f,b = 1.0f时,a + b直接舍入为a,结果错误;而手工写a + (b - a) / 2反而更稳 - 若真需抗溢出浮点中点,优先用
std::fma(a, 0.5, b * 0.5)(需<cmath></cmath>),或对量级做分支判断 - 别为了“统一写法”强行套用——浮点中点本就不该依赖
std::midpoint
指针中点才是不可替代的刚需场景
这是 std::midpoint 唯一无法被手写替代的用途:安全计算两个同类型指针的中间地址,彻底规避 ptrdiff_t 溢出风险。
- 手写
begin + (end - begin) / 2在极端大数组下,end - begin可能超出ptrdiff_t表示范围,导致未定义行为 -
std::midpoint(begin, end)要求指针指向同一数组(或 one-past-the-end),否则未定义 - 不支持
void*、不支持不同 const 修饰混用(如const int*和int*) - 二分查找中替换
(low + high) / 2时,确保low和high都是同类型指针,而非整数索引
最容易被忽略的是:它只管算术安全,不管业务语义。比如二分查找里 std::midpoint(low, high) 返回的地址,你仍得自己判断是否越界、是否满足循环不变量——函数本身不做任何校验。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











