为什么在C89中进行整数除法会得到不同的值?

5
例如,假设您有以下变量:
int i = 9;
int j = 7;

根据实现的不同,(-i)/j的值可能是-1-2。如何可能获得这两个不同的结果?


@Raphael 如果我们在谈论C99的话,是的,但我正在阅读的一本C语言书籍说,在C89中,如果你执行这样的计算,可能会得到不同的结果。 - Luis Averhoff
@LuisAverhoff,哪本书? - Arun A S
@ArunA.S C编程:现代方法第二版 - Luis Averhoff
2
投票关闭此问题的人:它为什么不是主题?如果这是一个重复的问题,我不会感到惊讶,但它肯定与编程有关。 - Keith Thompson
1
@KeithThompson 在我发布这个问题之前,我没有看到任何与此相关的问题,但可能被深深地埋在网站里了。 - Luis Averhoff
@KeithThompson 是的,那样更好。 - Luis Averhoff
2个回答

10

令人惊讶的是,C89中对此的结果是实现定义的:

ANSI草案 § 3.3.5

当整数相除且除法不精确时,如果两个操作数都是正数,则 / 运算符的结果是代数商小于最大整数,% 运算符的结果为正数。 如果任何一个操作数为负数,则无论代数商小于最大整数还是大于最小整数, / 运算符的结果都是实现定义的。

但是在C99中已经发生了改变:

N1256 § 6.5.5/6

当整数相除时,/ 运算符的结果是代数商去掉任何小数部分*

有一注脚:

* 这通常被称为“向零截断”

澄清一下,“实现定义”意味着实现必须决定哪个结果,这并不意味着有时会得到一种结果,有时会得到另一种结果(除非实现定义为执行像那样的奇怪操作)。


1
"Implementation-defined"也意味着实现必须记录其选择。 - Keith Thompson
我正在阅读 Ansi 草案,看到了这句话:"如果商 a/b 是可表示的,则表达式 (a/b)*b + a%b 应等于 a"。在这个上下文中, representable 这个词是什么意思? - Luis Averhoff
如果类型有准确地“成为”某些东西的能力,则0.5不能表示为int,就像1/3的结果不能表示为int一样。 - Ryan Haining
哦,好的现在我明白了。 - Luis Averhoff

5
在C89中,整数除法/的结果在负操作数情况下可能会被截断为向上或向下(在C99中,结果将被截断为朝零方向)。历史原因在C99理论基础中有所解释:
引用如下:

Programming Languages — C国际标准的理论基础 §6.5.5 乘法运算符

在C89中,涉及负操作数的整数除法可以以一种实现定义的方式向上或向下四舍五入;目的是为了避免在运行时代码中产生开销去检查特殊情况并强制实施特定行为。然而,在Fortran中,结果总是朝零方向截断,这样的开销似乎对数字编程社区来说是可接受的。因此,C99现在要求类似的行为,这应该有助于从Fortran到C的代码移植。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接