【问题标题】:How can I fix the cause of this compiler warning?如何解决此编译器警告的原因?
【发布时间】:2011-04-09 10:49:22
【问题描述】:

当我在 32 位系统上编译以下代码时,它会产生警告: 1087: warning: integer constant is too large for "long" type;我该如何解决这个问题,这样我就不会收到该警告并且它在 32 位上正常工作?

对此的有效输入是:

unsigned char str[] = "\x00\x17\x7c\x3a\x67\x4e\xcb\x01";

mypow 函数返回 unsigned long long。

     unsigned long long high, low, nano;
     high = // line 1087
         (str[7]&0xff) * mypow(2,56) +
         (str[6]&0xff) * mypow(2,48) +
         (str[5]&0xff) * mypow(2,40) +
         (str[4]&0xff) * mypow(2, 32);
     low =
         (str[3]&0xff) * mypow(2,24) +
         (str[2]&0xff) * mypow(2,16) +
         (str[1]&0xff) * mypow(2,8) +
         (str[0]&0xff);
     nano = ((high + low)/10000000) - (unsigned long long)11644473600;
     return localtime((time_t*)&nano);

【问题讨论】:

    标签: c 32bit-64bit


    【解决方案1】:

    如果您在代码中使用不适合 32 位的常量,请在其末尾添加 LL,以便编译器知道它应该是“long long”类型。例如,nano = 行末尾的常量应该是 11644473600LL。当前代码将常量转换为long long,但常量本身是常规的long,因为没有明确的LL 后缀。

    【讨论】:

    • 该语言保证如果常量不适合较小的类型,它将具有较大的类型。永远不需要添加任何后缀,除非您想强制为 small 常量赋予 larger 类型或从有符号切换到无符号。
    • 在这种特殊情况下,如果将 long 常量明确地赋予 LL 后缀,那么它又有什么意义呢?只是为了更简洁的代码,它可能有意义(即ULL 而不是演员表),但这取决于个人喜好。
    • 换句话说,这个答案并没有真正回答实际问题:为什么编译器会发出警告。正确答案很可能是因为 OP 在 C89/90 模式下编译,其中 long long 类型是非标准的。
    • @AndreyT- 大多数 32 位编译器不会(默认情况下)将常量解释为 64 位数字,除非您明确地将它们写成这样。由于常量11644473600 没有后缀,因此编译器将其解释为 long int 并抛出警告,因为该数字溢出了 long int。演员不是问题。如示例中所写,代码将 32 位数字转换为 64 位数字。编译器将数字解释为 32 位值是问题所在,将数字显式标记为“long long”会强制编译器将其视为 64 位数字。
    • 这种情况下警告的原因仅仅是支持long long作为标准类型。 C89/90 编译器不支持将long long 作为标准类型,这就是为什么他们根本无法隐式将此常量视为long long 而至少发出警告。同样,无论编译器是 32 位还是 64 位,这都适用。
    【解决方案2】:

    它认为 1000000 是一个 32 位的值。明确说明它很长:

    nano = ((high + low)/10000000L) - 11644473600L;
    

    编辑:ULL 是正确的后缀。

    【讨论】:

      【解决方案3】:

      我相信你需要做11644473600ULL

      【讨论】:

        【解决方案4】:

        您的问题最可能的正确答案是您必须在 C89/90 模式下使用您的 C 编译器(或者可能在 C++ 模式下?)。在 C89/90 和 C++ 中,最大的整数类型是 long。在这些语言中没有long long 这样的类型。然而,一些编译器支持long long 作为非标准扩展。当您在代码中使用对于long 类型而言太大的常量时,编译器必须拒绝您的代码或将该常量提升为非标准long long 类型。在后一种情况下,发出警告是为了通知您将非标准类型隐式引入您的代码中。

        虽然带有LL 或ULL 后缀的解决方案可能会抑制警告,但如果您真的想在代码中使用long long 类型,我仍然建议您在C99 模式下编译代码,这种类型是标准的。在 C99 模式下,无论任何后缀如何,警告都会自行消失。

        【讨论】:

          【解决方案5】:

          您应该使用stdint.h 定义的整数类型来实现跨平台可移植性。

          例如,您应该尝试使用uint64_t 而不是unsigned long long。这样您就可以确切地知道您获得了多少位,并且在所有平台上都是相同的。

          【讨论】:

          • 虽然确实如此,但 long long 保证至少为 64 位。然而,真正的问题是编译器认为 11644473600 字面量很长,但它不适合很长。
          • @nos - 你是对的。抱歉,我想我没有仔细阅读这个问题 :) 刚刚看到 32/64 位、整数类型、编译器警告……它点亮了我脑后的 stdint.h 小灯泡。
          【解决方案6】:

          在gcc 命令行上使用-std=c99,警告就会消失,因为对于这么大的整数常量,C99 具有明确定义的行为。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-01
            • 2020-07-17
            • 2020-02-16
            • 2012-06-14
            • 1970-01-01
            • 1970-01-01
            • 2020-11-25
            相关资源
            最近更新 更多