为什么以下表达式评估为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;
}
答案 0 :(得分:4)
这里的原因是0xFF
是32位signed int
而0xFFFFFFFFFFFFFFFF
可能是您平台上的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