Reputation: 115
int main()
{
unsigned char a = -1;
printf("%d",a);
printf("%u",a);
}
when i have executed the above program i got 255 255 as the answer.
we know negative numbers will be stored in 2's complement.
since it is 2's complement the representation would be
1111 1111
-->2's complement.
but in the above we are printing %d(int)
but integer is four bytes.
my assumption is even though it is character we are forcing compiler to treat it as integer. so it internally uses sign extension concept.
1111 1111 1111 1111 1111 1111 1111 1111
.
according to the above representation it has to be -1 in the first case since it is %d(signed). in the second case it has to print (2^31- 1) but it is printing 255 and 255. why it is printing 255 in both cases. tell me if my assumption is wrong and give me the real interpretation.
Upvotes: 0
Views: 632
Reputation: 6555
It is printing 255, simply because this is the purpose from ISO/IEC9899
H.2.2 Integer types
1 The signed C integer types int, long int, long long int, and the corresponding unsigned types are compatible with LIA−1. If an implementation adds support for the LIA−1 exceptional values ‘‘integer_overflow’’ and ‘‘undefined’’, then those types are LIA−1 conformant types. C’s unsigned integer types are ‘‘modulo’’ in the LIA−1 sense in that overflows or out-of-bounds results silently wrap. An implementation that defines signed integer types as also being modulo need not detect integer overflow, in which case, only integer divide-by-zero need be detected.
If this is given, printing 255 is absolutly that, what the LIA-1 would expect.
Otherwise, if your implementation doesn't support C99's LIA-1 Annex part, then its simply undefined behaving.
Upvotes: 0
Reputation: 19874
unsigned char
runs from 0-255
So the negative number -1
will print 255
-2
will print 254
and so on...
signed char
runs from -128 to +127
so you get -1 for the same printf()
which is not the case with unsigned char
Once you make a assignment to a char then the rest of the integer values will be padded so your assumption of 2^31
is wrong.
The negative number is represented using 2's complement(Implementation dependent)
So
1 = 0000 0001
So in order to get -1
we do
----------------------------------------
2's complement = 1111 1111 = (255) |
-----------------------------------------
Upvotes: 0
Reputation: 40645
Up to the representation of a
, you are correct. However, the %d
and %u
conversions of the printf()
function both take an int
as an argument. That is, your code is the same as if you had written
int main() {
unsigned char a = -1;
printf("%d", (int)a);
printf("%u", (int)a);
}
In the moment you have assigned -1
to a
you have lost the information that it once was a signed value, the logical value of a
is 255
. Now, when you convert an unsigned char
to an int
, the compiler preserves the logical value of a
and the code prints 255
.
Upvotes: 0
Reputation: 1273
The compiler doesn't know what type the extra parameters in printf
should be, since the only thing that specifies it should be treated as a 4-byte int
is the format string, which is irrelevant at compile time.
What actually happens behind the scenes is the callee (printf
) receives a pointer to each parameter, then casts to the appropriate type.
Roughly the same result as this:
char a = -1;
int * p = (int*)&a; // BAD CAST
int numberToPrint = *p; // Accesses 3 extra bytes from somewhere on the stack
Since you're likely running on a little endian CPU, the 4-byte int
0x12345678 is arranged in memory as | 0x78 | 0x56 | 0x34 | 0x12 |
If the 3 bytes on the stack following a
are all 0x00
(they probably are due to stack alignment, but it's NOT GUARANTEED), the memory looks like this:
&a: | 0xFF |
(int*)&a: | 0xFF | 0x00 | 0x00 | 0x00 |
which evaluates to *(int*)&a == 0x000000FF
.
Upvotes: 0
Reputation: 664
Your assumption is wrong; the character will "roll over" to 255, then be padded to the size of an integer. Assuming a 32-bit integer:
11111111
would be padded to:
00000000 00000000 00000000 11111111
Upvotes: 2