十六进制常量位移期间的C ++行为

时间:2015-11-13 14:35:06

标签: c++ bit-shift

为什么以下表达式评估为0xFFFFFFFFFF000000而不是0x00000000FF000000?我怎样才能获得0x00000000FF000000

#include <iostream>
#include <stdint.h> // uint64_t
#include <iomanip>  // std::setfill, std::setw

#define hexLOG(x) std::cout << std::showbase << std::internal << std::hex << std::uppercase << (x) << std::nouppercase << std::dec << std::endl;

int main ()
{

    hexLOG(0xFFFFFFFFFFFFFFFF & (0xFF << (8 * 3)));

    return 0;
}

更新

我创建了以下示例,以便您可以看到两种方法之间的区别:

#include <iostream>
#include <stdint.h> // uint64_t
#include <iomanip>  // std::setfill, std::setw

#define hexLOG(x) std::cout << std::showbase << std::internal << std::hex << std::uppercase << (x) << std::nouppercase << std::dec << std::endl;

int main ()
{
    uint64_t mask = 0xFF;

    hexLOG("   mask:", (mask << 56));
    hexLOG("   mask:", (0xFFu << 56));
    hexLOG("   mask:", (0xFFull << 56));

    return 0;
}

2 个答案:

答案 0 :(得分:4)

这里的原因是0xFF是32位signed int0xFFFFFFFFFFFFFFFF可能是您平台上的64位signed long long。当您执行&操作时,已移位的0xFF(当时将保留值0xFF000000)会被提升为64位signed long long,此时符号 - 扩展是为了保留0xFF000000代表您平台上的负数的事实。

通常,左移一个正signed整数以使符号位受到影响是未定义的行为。通常应该使用unsigned类型进行位移操作。您可以将u后缀添加到十六进制文字的末尾,以使其成为无符号文字:0xFFu

答案 1 :(得分:2)

这是签名/未签名的问题。默认情况下,(来自内存)常量的类型为int。 编辑:继续评论我看得更深,当然,我错了。正如Jordan Melo,Slava和molbdnilo所指出的那样,问题不是数字符号扩展的结果,而是整数推广之一。

以下是解决方案:

#include <iostream>

#define hexLOG(x) std::cout << std::showbase << std::internal << std::hex << std::uppercase << (x) << std::nouppercase << std::dec << std::endl;

int main (void)
{
    unsigned int inputVar = 0xFF;

    hexLOG(0xFFFFFFFFFFFFFFFF & (inputVar << (8 * 3)));

    return 0;
}

以下是生成的程序集中signed关键字造成的差异:

签名

main:
    push    rbp
    mov rbp, rsp
    push    rbx
    sub rsp, 24
    mov DWORD PTR [rbp-20], 255
    mov eax, DWORD PTR [rbp-20]
    sal eax, 24
    movsx   rbx, eax      ; mov 32bit eax into 64 bit rbx with sign extension

无符号整数

main:
    push    rbp
    mov rbp, rsp
    push    rbx
    sub rsp, 24
    mov DWORD PTR [rbp-20], 255
    mov eax, DWORD PTR [rbp-20]
    sal eax, 24
    mov ebx, eax          ; mov 32 bit eax into 32 bit ebx