除以零:未定义的行为或实现在C和/或C ++中定义?

时间:2010-06-09 08:19:27

标签: c++ c undefined-behavior divide-by-zero

关于除零,标准说:

  

C99 6.5.5p5 - /运算符的结果是第一个操作数除以第二个操作数的商; %运算符的结果是余数。在这两个操作中,如果第二个操作数的值为零,则行为未定义。

     

C ++ 03 5.6.4 - 二进制/运算符产生商,而二进制%运算符从第一个表达式除以第二个表达式得到余数。如果/或%的第二个操作数为零,则行为未定义。

如果我们将上述段落视为面值,那么两种语言的答案显然都是 Undefined Behavior 。但是,如果我们进一步了解C99标准,我们会看到以下段落似乎是矛盾的(1):

  

C99 7.12p4 - 宏INFINITY扩展为float类型的常量表达式,表示正或无符号无穷大(如果可用);

标准是否有某种黄金法则,其中未定义的行为不能被(可能)矛盾的陈述所取代?除此之外,我认为如果你的实现定义了INFINITY宏,那么将零除法定义为这样是不合理的。但是,如果您的实现定义此类宏,则行为为Undefined。

我很好奇这两种语言在这个问题上的共识是什么(如果有的话)。如果我们讨论整数除法int i = 1 / 0与浮点除法float i = 1.0 / 0.0,答案是否会改变?

注意(1) C ++ 03标准讨论了包含INFINITY宏的<cmath>库。

8 个答案:

答案 0 :(得分:23)

我没有看到任何矛盾。除以零是未定义的,期间。没有提及“......除非在引用文本中的任何地方定义了INFINITY”

请注意,在数学中没有定义1/0 = 无穷大。一个可能以这种方式解释它,但它是一种个人的,“捷径”式的解释,而不是一个合理的事实。

答案 1 :(得分:12)

1/0不是无穷大,只有

lim 1/x = ∞ (x -> +0)

答案 2 :(得分:4)

为什么会这样?

这在数学上没有意义,并不是说1 / x 在数学中一般被定义为∞。此外,您至少还需要两种情况:-1 / x 和0 / x 也不能等于∞。

一般情况下请参阅division by zero,特别是computer arithmetic部分。

答案 3 :(得分:3)

这不是一个数学最纯粹的问题,而是一个C / C ++问题。

  • 根据IEEE 754标准,所有现代C编译器/ FPU都使用,我们有
    • 3.0 / 0.0 = INF
    • 0.0 / 0.0 = NaN
    • -3.0 / 0.0 = -INF

FPU将有一个状态标志,如果需要,您可以将其设置为生成异常,但这不是常态。

当INF是有用的结果时,INF对于避免分支非常有用。见这里的讨论

http://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF

答案 4 :(得分:1)

我只获得了C99选秀权。在§7.12/ 4中它说:

  

    INFINITY
     

扩展为常量表达式   类型float表示积极或   无符号无穷大,如果有的话;其他   到float类型的正常数   在翻译时溢出。

注意INFINITY可以根据浮点溢出来定义,不一定是被零除。

答案 5 :(得分:1)

对于INFINITY宏:在IEEE754标准中有一个显式编码来表示+/-无穷大,即如果所有指数位都被置位且所有分数位被清除(如果设置了一个分数位,它代表NaN)

使用我的编译器(int) INFINITY == -2147483648,如果返回INFINITIY,则计算结果为int i = 1/0的表达式肯定会产生错误的结果

答案 6 :(得分:1)

定义__STDC_IEC_559__的实现需要遵守附件F中给出的要求,这些要求又要求符合IEC 60559的浮点语义。该标准对浮点除法的行为没有要求在没有定义__STDC_IEC_559__的实现上为零,但对于那些定义它的实现则为零。在IEC 60559指定行为但C标准不指定行为的情况下,C标准要求编译器定义__STDC_IEC_559__,以符合IEC标准中的描述。

根据IEC 60559(或美国标准IEEE-754)的定义,0为零的除法产生NaN,将浮点数除以正零或字典常数0,得到与被除数具有相同符号的INF值并且将浮点数除以负零会产生一个符号相反的INF。

答案 7 :(得分:0)

底线,C99(根据你的引言)在&#34;实现定义的&#34;的上下文中没有说任何关于INFINITY的内容。其次,你所引用的内容并未显示&#34;未定义行为的不一致含义&#34;。


[引用维基百科的未定义行为页面]&#34;在C和C ++中,还使用了实现定义的行为,其中语言标准未指定行为,但实现必须选择行为和需要记录并遵守它所选择的规则。&#34;

更准确地说,标准意味着&#34;实施定义&#34; (我认为只是)当它使用那些关于自#34;实现定义&#34;是标准的特定属性。 C99 7.12p4的引用没有提到&#34;实现定义&#34;。

[来自C99标准(迟到草案)]&#34;未定义的行为:使用不可移植或错误的程序结构或错误数据时的行为,本国际标准没有规定任何要求&#34;

请注意,没有要求&#34;强加给未定义的行为!

[C99 ..]&#34;实现定义的行为:未指定的行为,其中每个实现都记录了如何做出选择&#34;

[C99 ..]&#34;未指明的行为:使用未指定的值,或本国际标准提供两种或更多种可能性的其他行为,并且在任何情况下都不会对其进行任何进一步的要求&#34;

文档是实现定义行为的必要条件。