In a portion of my program, I'll have to manage signed 8-bit integers. I have no problem to display them as decimals using printf
and %d
formatting.
However, when it comes to hexadecimal representation, the formatting of a negative int8_t
variable is not shown as a 8-bit hexadecimal (0xXX
) but as a 32-bit hexadecimal (0xFFFFFFXX
).
Here is the snippet of code, describing my problem:
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02X\n", value, value);
t = 127;
printf("t = %d = 0x%02X\n", value, value);
t = -128;
printf("t = %d = 0x%02X\n", value, value);
return 0;
}
Compilation and execution give:
t = 0 = 0x00
t = 127 = 0x7F
t = -128 = 0xFFFFFF80
I would like to get 0x80
and not 0xFFFFFF80
. What did I do wrong? How to display the negative signed 8-bit integer as a 8-bit hexadecimal?
The problematic 'sign extension' is happening because, for your %X
format specifier, the expected argument type is of int size, so your int_8
argument, after being suitably promoted (and sign-extended), is then printed as a 'full-size' unsigned integer.
You can prevent the latter part by adding the hh
length modifier to the format, which indicates that the corresponding argument is of char
size, so only the least-significant byte will be printed:
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02hhX\n", value, value);
value = 127;
printf("t = %d = 0x%02hhX\n", value, value);
value = -128;
printf("t = %d = 0x%02hhX\n", value, value);
return 0;
}
Further Reference
Note: As pointed out in the comments here, and in other answers, the use of the %X
format specifier (with or without a length modifier) for an argument of signed type is, formally, undefined behaviour (though it will likely work on the vast majority of modern systems).
To avoid such potential UB, a better way to achieve your goal is to explicitly cast your int8_t
argument(s) to the unsigned equivalent (of the same bit size – or uint8_t
, in your case). Then, when the "default argument promotion" is applied, it will be performed without sign extension (as all possible values of a uint8_t
are representable in an int
); thus, there will then be no need to add the hh
length modifier to your format, as the upper (added) bits of the resultant unsigned int
values will not be set.
This code gives your desired result in a well-defined way:
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = 127;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = -128;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With