如何解决C++中比较大小时出现的算术溢出警告?
编译以下C++代码时,条件判断语句if ((payload_size + 1U) * 2 > fw_remaining_size - sizeof(stRecord))处触发两条C26451算术溢出警告,要求在**不使用static_cast<size_t>(payload_size)**的前提下解决这些警告。
示例代码:
#include <iostream> #include <cstdio> #include <cstdint> int main() { struct stRecord { uint8_t SType; uint8_t TypeNo; uint8_t Length[2]; uint8_t Address[8]; }; uint8_t payload_size = 37; size_t fw_remaining_size = 80; if ((payload_size + 1U) * 2 > fw_remaining_size - sizeof(stRecord)) { } return 0; }
警告信息:
C26451: 算术溢出:对4字节值使用运算符'*',然后将结果转换为8字节值。 在调用运算符'*'之前将值转换为更宽的类型以避免溢出 (io.2)。 C26451: 算术溢出:对4字节值使用运算符'+',然后将结果转换为8字节值。 在调用运算符'+'之前将值转换为更宽的类型以避免溢出 (io.2)。
警告的根源是:payload_size是uint8_t(1字节类型),和1U(unsigned int,4字节)相加后结果为4字节类型,再乘以2还是4字节,最后和8字节的size_t类型比较时才会被提升。编译器担心4字节运算阶段可能发生溢出,因此触发警告。
要在不直接转换payload_size的前提下解决问题,核心是让整个算术运算在size_t(或兼容的宽字节类型)的上下文里进行,避免窄字节运算阶段的溢出风险。
方案1:用宽字节字面量触发类型提升
在表达式开头加入0ULL(unsigned long long,通常和64位系统的size_t兼容),让payload_size自动提升为宽字节类型:
if ((0ULL + payload_size + 1) * 2 > fw_remaining_size - sizeof(stRecord))
0ULL是8字节无符号类型,payload_size会被隐式提升为同类型,后续的+1和*2都在8字节宽度下进行,不会触发溢出警告。
方案2:用size_t类型的常量参与运算
把1U换成size_t类型的常量,让加法运算直接在size_t宽度下进行:
if ((payload_size + static_cast<size_t>(1)) * 2 > fw_remaining_size - sizeof(stRecord))
这里仅转换了常量1,没有转换payload_size,符合要求。也可以用size_t{1}替代static_cast<size_t>(1),写法更简洁:
if ((payload_size + size_t{1}) * 2 > fw_remaining_size - sizeof(stRecord))
方案3:调整运算顺序(需注意场景)
把表达式改写为等价形式,让payload_size的运算提前适配宽字节范围:
if (payload_size * 2 + 2 > fw_remaining_size - sizeof(stRecord))
注:该方案仅在payload_size最大值(255)乘以2不会超出当前系统int范围时适用,前两种方案的兼容性更强。
内容的提问来源于stack exchange,提问作者prakash

