Lua中800000000加3000000000得-2147483648的问题如何修复
问题产生原因
这个现象是典型的32位有符号整数溢出:
- 传入的两个数值实际求和结果为
800000000 + 3000000000 = 3800000000 - 32位有符号整数可存储的数值范围是
-2^31到2^31-1,即-2147483648到2147483647,3800000000已经远超该类型上限 - 标准Lua默认用双精度浮点数存储数值,可精确表示的整数上限达2^53,本身不会出现这类溢出问题。该异常只会出现在嵌入宿主程序(常见为游戏客户端/服务端引擎)的定制Lua环境中:经验值字段在底层C/C++逻辑中被定义为32位有符号整型,加法运算在底层执行时触发补码回绕溢出,最终回传给Lua层的计算结果就是溢出后的负数
-2147483648 - 原代码中的判断逻辑
if actorExp + val完全无法拦截异常:Lua中仅nil和false会被判定为假,负数属于真值,根本不会走到返回分支。
修复方案
- 加法前做溢出预判,避免直接计算触发溢出
提前判断相加后是否会超过32位整数上限,如果超过就直接钳位到允许的最大值,参考实现:local INT32_MAX = 2147483647 -- 32位有符号整数上限 function addExp(actorExp, val) -- 过滤非法入参 if type(actorExp) ~= "number" or type(val) ~= "number" or actorExp < 0 or val < 0 then return end -- 提前判定溢出场景 if actorExp > INT32_MAX - val then actorExp = INT32_MAX else actorExp = actorExp + val end updateInfo(actor) end - 调整底层存储类型
如果业务设计中经验值上限确实会超过21亿,直接把底层C/C++层存储经验值的字段类型从32位int修改为64位整型long long,或者直接使用双精度浮点数存储,从根源上消除小类型溢出的可能。 - 增加异常值兜底
如果业务允许经验值封顶,也可以在每次赋值后增加负数校验,一旦检测到值为负直接设置为对应系统的经验上限,避免异常负值传导到后续展示、结算逻辑。
内容的提问来源于stack exchange,提问作者Phát papa
相关产品推荐
相关产品推荐

