#include <stdio.h>
int main() {
int i,n;
int a = 123456789;
void *v = &a;
unsigned char *c = (unsigned char*)v;
for(i=0;i< sizeof a;i++) {
printf("%u ",*(c+i));
}
char *cc = (char*)v;
printf("\n %d", *(cc+1));
char *ccc = (char*)v;
printf("\n %u \n", *(ccc+1));
}
This program generates the following output on my 32 bit Ubuntu machine.
21 205 91 7
-51
4294967245
First two lines of output I can understand =>
please explain the last line of output. WHY three bytes of 1's are added
because (11111111111111111111111111001101) = 4294967245
.
unsigned char ch = 'a'; Initializing an unsigned char: Here we try to insert a char in the unsigned char variable with the help of ASCII value. So the ASCII value 97 will be converted to a character value, i.e. 'a' and it will be inserted in unsigned char.
All signed character values range from -128 to 127. All unsigned character values range from 0 to 255. The /J compiler option changes the default type for char from signed char to unsigned char .
'%u' treats the integer as unsigned, whereas '%d' treats the integer as signed.
Some properties of the signed char data type are: It is generally used to store 8-bit characters. Being a signed data type, it can store positive values as well as negative values. Size of 8 bits is occupied where 1 bit is used to store the sign of the value.
Apparently your compiler uses signed characters and it is a little endian, two's complement system.
123456789d = 075BCD15h
Little endian: 15 CD 5B 07
Thus v+1 gives value 0xCD
. When this is stored in a signed char, you get -51
in signed decimal format.
When passed to printf, the character *(ccc+1)
containing value -51
first gets implicitly type promoted to int
, because variadic functions like printf has a rule stating that all small integer parameters will get promoted to int
(the default argument promotions). During this promotion, the sign is preserved. You still have value -51, but for a 32 bit signed integer, this gives the value 0xFFFFFFCD
.
And finally the %u
specifier tells printf to treat this as an unsigned integer, so you end up with 4.29 bil something.
The important part to understand here is that %u
has nothing to do with the actual type promotion, it just tells printf how to interpret the data after the promotion.
-51
store in 8 bit hex is 0xCD
. (Assuming 2s compliment binary system)
When you pass it to a variadic function like printf
, default argument promotion takes place and char
is promoted to int
with representation 0xFFFFFFCD
(for 4 byte int).
0xFFFFFFCD
interpreted as int
is -51
and interpreted as unsigned int
is 4294967245
.
Further reading: Default argument promotions in C function calls
please explain the last line of output. WHY three bytes of 1's are added
This is called sign extension. When a smaller signed number is assigned (converted) to larger number, its signed bit get's replicated to ensure it represents same number (for example in 1s and 2s compliment).
Bad printf
format specifier
You are attempting to print a char
with specifier "%u"
which specifies unsigned [int]
. Arguments which do not match the conversion specifier in printf
is undefined behavior from 7.19.6.1 paragraph 9.
If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Use of char
to store signed value
Also to ensure char
contains signed
value, explicitly use signed char
as char
may behave as signed char
or unsigned char
. (In latter case, output of your snippet may be 205 205
). In gcc
you can force char
to behave as unsigned char
with -funsigned-char
option.
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