Reputation: 7610
I have compiled the following C Program in Code::Blocks 10.05 on Windows 7.
int main()
{
unsigned char a=-5;
signed char b=-5;
char c=-5;
printf("%d %d %d \n",a,b,c);
printf("%u %u %u \n",a,b,c);
}
I expected the following output
251 -5 -5
251 251 251
I have reasoned like this,
-5 is represented as 1111 1011 in 2's Complement Notation. Hence 251 will be printed.
But I got the following output.
251 -5 -5
251 4294967291 4294967291
I know 4294967291 is the 32 bit 2's Complement representation of -5.
But why the unsigned char a is printed as 251 instead of 4294967291?
Upvotes: 3
Views: 227
Reputation: 36597
unsigned
integral types (including unsigned char
) work with modulo arithmetic. For unsigned char
, that is modulo UCHAR_MAX + 1
, where UCHAR_MAX
is an implementation-defined value in <limits.h>
with a typical value with most implementations of 255
(255
is also the minimum value that the standard permits for UCHAR_MAX
). Adding 256
to -5
(i.e. to get a remainder between 0
and 255
in order to initialise a
in your code) will explain why a
has a value of 251
.
As to why any of the values are printing at all, the values are being promoted to be of type int
when passed to printf()
. This promotion is unrelated to your format string but is what the %d
format specifier expects, so the values print as you see.
Upvotes: 2
Reputation: 16056
@Vality is slightly wrong in his answer. Because unsigned char
must hold values up to at least 255, then if uint8_t exists, CHAR_BIT
must be 8.
There's no reason to use the nasty PRI
macros, just use this:
unsigned char a = -5;
signed char b = -5;
char c = -5;
printf("%hhd %hhd %hhd \n", a, b, c);
printf("%hhu %hhu %hhu \n", a, b, c);
Upvotes: 1
Reputation: 6607
printf
is a variadic function, which causes (thanks to @TheParamagneticCroissant for the correction) the integral arguments to become promoted to int or unsigned int. Which according to the standard promotion rules will sign extend them appropriately. This is causing the numbers you are getting to be the results after this promotion process.
Instead you can use "%" PRIu8
to print 8 bit unsigned and "%" PRId8
to print 8 bit signed numbers. However beware that the arguments will still be promoted and then printf will downcast them again according to the format specifier, which may possibly still change that value but I am not sure of that from memory.
In addition char is not guaranteed in C to be 8 bit, it is better to include the <stdint.h>
header and use the proper fixed width types.
A fixed version of your code would be as so:
#include <stdint.h>
int main()
{
uint8_t a=-5;
int8_t b=-5;
printf("%" PRId8 "%" PRId8 "\n", a, b);
printf("%" PRIu8 "%" PRIu8 "\n", a, b);
}
Note I do not include an equivalent of a char as all the fixed width types are of defined sign so there is no direct equivalent of char, which is of undefined signedness.
Upvotes: 4