【问题标题】:Width of int64_t, is it always 64 bits?int64_t 的宽度,是否总是 64 位?
【发布时间】:2013-04-18 14:01:29
【问题描述】:

如下代码

static inline float fix2float(int64_t f)
{
    return (float)f / (1 << 60); // <-- error here
}

编译器给了我这些警告。

warning: left shift count >= width of type
warning: division by zero

为什么当 64 > 60 时编译器会给出这些警告?

【问题讨论】:

    标签: c gcc x86


    【解决方案1】:

    1 在您的 C 实现中不是 64 位数字。它是一个int,可能是 32 位。

    编译器不会查看表达式并看到其中涉及int64_t,因此其他算术应该使用 64 位。它从它们的部分构建表达式。在(1 &lt;&lt; 60) 部分中,编译器识别出一个并赋予它int 的类型,因为这是 C 规则所说的与简单常量值有关的内容(对于十六进制表示法、后缀和大值还有其他规则) .因此,1 &lt;&lt; 60 尝试将int 移动 60 位。由于您系统上的 int 只有 32 位,因此编译器会警告您。

    写这篇文章的更好方法是return f * 0x1p-60f;0x1p-60f 是一个 float 常量,值为 2–60

    【讨论】:

    • +1:我不知道 C99 十六进制指数的语法......(也就是说,我认为没有 prominent 代码的人不应该使用这种语法评论解释魔法)
    • @NormanGray:它已经成为语言的一部分 13 年。这几乎不是“魔法”。
    • 它是 C - 只有 13 年意味着它算得上是新奇事物(请记住,有些人仍然认为非 K&R C 是一个非常棒的想法)。但说真的,据我所知,这种语法对于 C 来说是独一无二的,而且至少有些晦涩难懂,因此对代码的最终读者来说,一个突出的注释将是礼貌的。
    【解决方案2】:

    在您的代码中,存在实际上与 int64_t 无关的错误。在 (1 &lt;&lt; 60) 表达式中,160 都被视为 int(通常为 32 位)。您应该使用修饰符LL。 类似于 (1LL

    #include <stdio.h>
    
    int main()
    {
        printf("%llx\n", (1LL << 60));
        return 0;
    }
    

    顺便请注意printf()格式。 int64_t 实际上是 long long(至少在大多数情况下)。

    更新:有社区声音建议使用稍微不同的方法:

    printf("%" PRIx64 "\n", (UINT64_C(1) << 60));
    

    这里的问题至少在我所在的领域并非所有编译器都能正确实现这些宏(这里是one of possible proofs)。但是主流编译器应该很高兴。至少我不建议在 GCC 中混合使用 %lld1LL(你可以尝试,至少 GCC 4.6.3 抱怨这种混合)。

    【讨论】:

    • 在所有情况下,您都可以使用"%" PRId64 来格式化int64_t,无需假设它是long long 的别名。
    • 写入值为 1 的 int64_t 常量的正确方法是 INT64_C(1),而不是 1LL。当然,它的正确格式说明符是PRId64,如printf("%" PRId64 "\n",…);,在#include &lt;inttypes.h&gt; 之后。此外,x 用于未签名。如果你想用十六进制打印int64_t,你应该把它转换成uint64_t并用PRIx64打印。
    猜你喜欢
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    相关资源
    最近更新 更多