如何无分支实现两个uint16_t相加并避免溢出?
无分支实现方案
可以利用无符号整数溢出的定义特性(C标准规定无符号整数溢出是模2^N的合法运算),结合位运算实现无分支逻辑,避免条件跳转。以下是实现代码:
#include <stdint.h> uint16_t add_with_no_overflow(uint16_t num, uint16_t delta) { uint16_t sum = num + delta; // 无符号加法溢出时,sum会小于num(因为delta是正整数,正常相加sum >= num) uint16_t overflow_mask = -(sum < num); // 溢出时mask为0xFFFF,否则为0 // 溢出时返回UINT16_MAX,否则返回sum return (sum & ~overflow_mask) | (UINT16_MAX & overflow_mask); }
逻辑解释
- 溢出判断:无符号整数加法中,若
num + delta溢出,结果会是(num + delta) % 65536,必然小于num(因为delta是正的,正常相加结果不会小于原数)。因此sum < num可以直接作为溢出的判断条件。 - 掩码生成:在无符号运算中,
-(sum < num)会将布尔值转换为全1或全0的掩码:当条件为真(溢出)时,sum < num的值为1,取负后无符号下是0xFFFF;条件为假时,值为0,取负后还是0。 - 结果选择:通过位运算,溢出时用
UINT16_MAX覆盖sum,否则直接返回sum,全程没有分支跳转。
另一种等价实现
也可以基于原分支逻辑的条件直接生成掩码,避免先计算sum:
#include <stdint.h> uint16_t add_with_no_overflow(uint16_t num, uint16_t delta) { uint16_t overflow_mask = -(num > UINT16_MAX - delta); uint16_t sum = num + delta; return (sum & ~overflow_mask) | (UINT16_MAX & overflow_mask); }
为什么max(num+delta, num)不适用
你之前尝试的方案在溢出时num+delta会小于num,max会返回原num,但需求是溢出时返回UINT16_MAX,因此无法满足要求。而上面的无分支方案通过掩码精准替换了溢出时的结果。
内容的提问来源于stack exchange,提问作者Jonathan Levin
相关产品推荐
相关产品推荐

