C语言int变量三次连乘赋值给long为何发生整数溢出?
核心结论
你的判断完全准确:C语言中算术表达式的求值类型由参与运算的操作数类型决定,和最终赋值的目标类型没有关系。赋值触发的类型转换,只会在右侧整个表达式全部计算完成后才执行,不会提前改变运算过程中的中间值类型。
溢出原因拆解
你给出的问题代码如下:
void main(void) { int n = 1291; long cube = n*n*n; printf("Cube: %ld, n: %d", cube, n); }
n*n*n是左结合的算术运算,会按照以下顺序分步求值,全程在int类型下计算:
- 第一步计算
n * n:两个操作数均为int,结果类型为int。1291的平方是1666681,处于32位int的取值范围(-2147483648 ~ 2147483647)内,这一步无异常。 - 第二步计算上一步结果 * n:两边操作数依然是
int,结果类型仍为int。此时乘积为2151685171,超过32位int的最大值2147483647,触发有符号整数溢出,得到补码截断后的错误值-2143282125。 - 等整个连乘运算完成、溢出的错误结果已经生成后,才会执行赋值阶段的类型转换,把这个错误的
int值转为long存入cube变量,此时已经无法得到正确结果。
这也是你把n的类型改为long后运行正常的原因:当n本身是long类型时,每一步乘法的操作数都是long,中间结果也会按long类型存储,全程不会触发int范围的溢出,自然能得到正确的计算值。
修复方法
不需要把n整体声明为long,只要在链式运算的第一步将任意一个操作数强转为long,就能让后续所有运算自动提升到long精度,避免溢出:
void main(void) { int n = 1291; long cube = (long)n * n * n; printf("Cube: %ld, n: %d", cube, n); }
运行后可得到预期输出:
Cube: 2151685171, n: 1291
注意:不要把强转写为
(long)(n*n*n),这种写法是先完成int类型的连乘、已经触发溢出后再做类型转换,和原错误写法没有区别。
内容的提问来源于stack exchange,提问作者s3dev
相关产品推荐
相关产品推荐

