Why is the following expression evaluated as 0xFFFFFFFFFF000000
, instead of 0x00000000FF000000
? How can I get 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;
}
I have create the following example so that you can see the difference between the two methods:
#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;
}
The reason here is that 0xFF
is a 32-bit signed int
and 0xFFFFFFFFFFFFFFFF
is probably a 64-bit signed long long
on your platform. When you perform the &
operation, the shifted 0xFF
(which at the time will hold the value 0xFF000000
) gets promoted to 64-bit signed long long
, at which point sign-extension takes place to preserve the fact that 0xFF000000
represents a negative number on your platform.
In general, left-shifting a positive signed
integer such that the sign bit is affected is undefined behaviour. You should normally use unsigned
types for bit shifting operations. You can add the u
suffix to the end of your hex literals to make them unsigned literals: 0xFFu
.
It's a signed/unsigned issue. By default, (from memory) a constant is of type int. EDIT: Further to the comments I've looked deeper and of course, I was wrong. As pointed out by Jordan Melo, Slava and molbdnilo, the issue isn't as a result of sign extension of the number, but rather, one of integer promotion.
Here's the solution:
#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;
}
And here's the difference caused by the signed keyword on the resulting assembly:
Signed 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
Unsigned 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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.