【问题标题】:When do we need to mention/specify the type of integer for number literals?我们什么时候需要提及/指定数字文字的整数类型?
【发布时间】:2012-05-02 04:57:55
【问题描述】:

我遇到了如下代码:

#define SOME_VALUE 0xFEDCBA9876543210ULL

这个SOME_VALUE 稍后被分配给一些unsigned long long

问题

  1. 在这种情况下是否需要像ULL 这样的后缀?
  2. 什么情况下我们需要指定使用的整数类型?
  3. 在这种情况下,C 和 C++ 的行为是否不同?

【问题讨论】:

    标签: c++ c types integer


    【解决方案1】:

    在 C 中,十六进制文字获取第一种类型的 intunsigned intlongunsigned longlong longunsigned long long,如果它没有后缀,则可以表示其值。如果 C++ 有相同的规则,我不会感到惊讶。

    如果你想给一个字面量一个比默认值更大的类型,或者你想强制它的签名,你需要一个后缀,例如

    1 << 43;
    

    如果没有后缀,那(几乎可以肯定)是未定义的行为,但例如 1LL &lt;&lt; 43; 就可以了。

    【讨论】:

    • 我怀疑1 &lt;&lt; 43 的行为几乎肯定不是未定义的(意味着它可能会炸毁您的计算机),但很可能是不可移植的(意味着它可能在我的计算机上与您的计算机上做不同的事情)。
    • 第 6.5.7 节(n1570):“如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。”除非您的 int 至少有 43 位,否则它是未定义的行为。它可能会产生 0 或 512,但它是未定义的。
    • @Gabe:未定义。一些处理器捕获算术溢出。我怀疑任何人都会被设计炸毁,但它可能会杀死程序。
    • 所以未定义行为是否未定义。在具有 64 位整数的体系结构上,行为已定义,而在具有 32 位整数的体系结构上,行为未定义。我想我应该预料到的。在我的电脑上1 &lt;&lt; 43 == 2048.
    • @Gabe:直到 20 世纪中期,99.9% 的 32 位编译器会将 1&lt;&lt;43 评估为 ARBITRARY_VALUE ? (1&lt;&lt;11) : 0,没有副作用;他们不一定会在何时返回 2048 和何时返回零保持一致,但他们不会做任何其他事情。然而,现代编译器可能会忽略任何代码,这些代码只有在程序接收到会导致过大移位(或导致其他 UB)的数据时才相关,这当然可能会使程序中的其他所有内容变得毫无意义。
    【解决方案2】:
    1. 我认为不需要,但也许那是那个编译器所必需的。
    2. 例如,printf("%ld", SOME_VALUE); 如果未指定 SOME_VALUE 的整数类型,则可能会导致输出错误。

    【讨论】:

      【解决方案3】:

      在 C++ 中使用指定后缀的一个很好的例子是重载函数。举个例子:

      #include <iostream>
      
      void consumeInt(unsigned int x)
      {
          std::cout << "UINT" << std::endl;
      }
      
      void consumeInt(int x)
      {
          std::cout << "INT" << std::endl;
      }
      
      void consumeInt(unsigned long long x)
      {
          std::cout << "ULL" << std::endl;
      }
      
      int main(int argc, const char * argv[])
      {
          consumeInt(5);
          consumeInt(5U);
          consumeInt(5ULL);
      
          return 0;
      }
      

      结果:

      INT
      UINT
      ULL

      【讨论】:

        【解决方案4】:

        当您不提及任何后缀时,编译器会推断出整数文字的类型为int。由于某些整型文字如果推断其类型为int 可能会溢出,因此您添加后缀以告诉编译器推断类型为int 以外的类型。这就是你写0xFEDCBA9876543210ULL时所做的。

        写浮点数时也可以使用后缀。 1.2double,而 1.2f 是浮点数。

        【讨论】:

        • 不,根据值选择类型。
        • @R..:我不认为这在 C++ 中是正确的。
        • @Nawaz 是的。 C++ 在这里与 C 相同,参见标准的第 2.14.2 节。
        【解决方案5】:

        如果您的唯一目的是获得数字的正确,则不需要后缀; C 会自动选择适合该值的类型。

        如果你想强制表达式的类型,后缀很重要,例如出于它如何在表达式中交互的目的。当您要执行会溢出较小类型(例如,1ULL&lt;&lt;nx*10LL)的算术运算时,可能需要将其设为 long 或 long long,并且当您想要将其设为无符号时很有用表达式作为一个整体具有无符号语义(例如,c-'0'&lt;10Un%2U)。

        【讨论】:

          猜你喜欢
          • 2012-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-28
          • 2011-09-20
          • 2019-07-17
          相关资源
          最近更新 更多