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

C++ behaviour during hex constant bit shifting

本文关键字:C++ 行为 常量 十六进制      更新时间:2023-10-16

为什么以下表达式求值为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;
}

这里的原因是0xFF是您平台上的32位signed int,而0xFFFFFFFFFFFFFFFF可能是64位signed long long。执行&操作时,移位后的0xFF(此时将保持值0xFF000000)将升级为64位signed long long,此时会进行符号扩展,以保留0xFF000000在平台上表示负数的事实。

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

这是一个已签名/未签名的问题。默认情况下,(从内存中)常量的类型为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;
}

下面是由生成的程序集上的签名关键字引起的差异:

有符号int

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

无符号int

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