【问题标题】:bits shift exceeding width of type in C [duplicate]位移超过C中类型的宽度[重复]
【发布时间】:2021-11-01 13:16:08
【问题描述】:

我有一个名为 vpn 的 uint64_t 变量,我正在尝试获取它的左 9 位。 我知道 vpn 是 45 位长,所以我尝试了以下方法:

uint64_t nineMSB = (vpn & (511 << 36)) >> 36;

但我收到以下警告:

left shift count >= width of type

这是为什么呢? 511 是二进制的 9 个,所以 511

谢谢!

【问题讨论】:

  • 511 的类型为 int。试试511ULL
  • 511int。试试511ull

标签: c operating-system bit bit-shift integer-overflow


【解决方案1】:

常量511 的类型为int。您的系统很可能有一个 32 位的int,因此这意味着您将一个值移动的量大于其位长。这样做会触发undefined behavior

这是由C standard 的第 6.5.7p3 节关于按位移位运算符规定的:

对每个操作数执行整数提升。方式 结果是提升的左操作数的结果。 如果 右操作数的值为负数或大于或 等于提升的左操作数的宽度,行为是 未定义。

您可以通过在常量上使用ULL 后缀来解决此问题,这将为其提供类型unsigned long long,保证至少为64 位长度。

uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;

【讨论】:

    【解决方案2】:

    没有任何后缀或前缀的整数常量的类型为int。在许多系统上,int 的长度为 32 位,但也可以只有 16 位(avr 端口)。

    uint64_t foo(uint64_t vpn)
    {
        uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;
        return nineMSB;
    }
    
    uint64_t foo1(uint64_t vpn)
    {
        uint64_t nineMSB = (vpn & ((uint64_t)511 << 36)) >> 36;
        return nineMSB;
    }
    

    【讨论】:

    • Re“不带任何后缀的整数常量的类型为int”:类型取决于值和形式(例如,十六进制),而不仅仅是后缀或缺少后缀。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多