问题
#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 =>
- 1st Line : sequence of storing of bytes in memory.
- 2nd Line : signed value of the second byte value (2's complement).
- 3rd Line : why such a large value ?
please explain the last line of output. WHY three bytes of 1's are added
because (11111111111111111111111111001101) = 4294967245
.
回答1:
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.
回答2:
-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.
来源:https://stackoverflow.com/questions/36350405/reading-signed-char-using-u