【问题标题】:C: Implicit casting and integer overflowing in the evaluation of expressionsC:表达式求值中的隐式转换和整数溢出
【发布时间】:2010-09-08 05:01:25
【问题描述】:

我们来看看代码

int a, b, c;
...
if ((a + b) > C)

如果我们将 a 和 b 的值相加,并且总和超过了 int 的最大值,是否会影响比较的完整性?我在想可能有一个隐式的向上转换或溢出位检查,这将被考虑到这个表达式的评估中。

【问题讨论】:

    标签: c


    【解决方案1】:

    如果向上转换没有获得任何位(不能保证 sizeof(long)>sizeof(int) 在 C 中),您可以使用如下条件来比较和检查溢出 - 向上转换几乎肯定更快不过,如果你能用的话。

    #if !defined(__GNUC__) || __GNUC__<2 || (__GNUC__==2 && __GNUC_MINOR__<96)
    #   define unlikely(x) (x)
    #else
    #   define unlikely(x)     (__extension__ (__builtin_expect(!!(x), 0)))
    #endif
    
    /* ----------
     * Signed comparison (signed char, short, int, long, long long)
     * Checks for overflow off the top end of the range, in which case a+b must
     * be >c.  If it overflows off the bottom, a+b < everything in the range. */
    if(a+b>c || unlikely(a>=0 && b>=0 && unlikely(a+b<0)))
        ...
    
    /* ----------
     * Unsigned comparison (unsigned char, unsigned short, unsigned, etc.)
     * Checks to see if the sum wrapped around, since the sum of any two natural
     * numbers must be >= both numbers. */
    if(a+b>c || unlikely(a+b<a))
        ...
    
    /* ----------
     * To generate code for the above only when necessary: */
    if(sizeof(long)>sizeof(int) ? ((long)a+b>c)
           : (a+b>c || unlikely(a>=0 && b>=0 && unlikely(a+b<0)))
        ...
    

    宏或内联函数的绝佳候选者。您可以根据需要提取“不太可能”,但它们可以帮助缩小和加快 GCC 生成的代码。

    【讨论】:

      【解决方案2】:

      测试确认 GCC 4.2.3 将简单地与溢出的结果进行比较:

      #include <stdio.h>
      
      int main()
      {
          int a, b, c;
      
          a = 2000000000;
          b = 2000000000;
          c = 2100000000;
      
          printf("%d + %d = %d\n", a, b, a+b);
          if ((a + b) > c)
          {
              printf("%d + %d > %d\n", a, b, c);
          }
          else
          {
              printf("%d + %d < %d\n", a, b, c);
          }
          return 0;
      }
      

      显示以下内容:

      2000000000 + 2000000000 = -294967296
      2000000000 + 2000000000 < 2100000000
      

      【讨论】:

        【解决方案3】:

        请参阅 K&R 书中的第 2.7 节,类型转换

        【讨论】:

          【解决方案4】:

          我相信这可能是特定于平台的。查看有关如何处理溢出的 C 文档...

          啊,是的,向上转型不会自动发生……

          【讨论】:

            【解决方案5】:

            C 不会做这样的事情。它会悄悄溢出并导致可能不正确的比较。您可以自己向上转换,但不会自动完成。

            【讨论】:

            • 同意!没有自尊的 C 编译器会这样做。悄悄溢出宝贝!我们不会有任何其他方式。毕竟,这就是 C 的伟大之处。
            • 溢出是未定义的行为,因此编译器可以处理它的一种方法是默默地创建一个更大的类型并使用该更大的类型评估表达式的其余部分。我知道没有编译器会这样做,这样做只会鼓励人们编写具有未定义行为的糟糕代码.. :-)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-11
            • 1970-01-01
            • 2014-11-15
            • 1970-01-01
            • 1970-01-01
            • 2018-12-01
            相关资源
            最近更新 更多