Reputation: 581
Here is the code:
#include<stdio.h>
void f(unsigned char v)
{
char c = v;
unsigned char uc = v;
printf("%%X: %X, %X\n", c, uc);
}
int main(int argc, char *argv[])
{
f(0x80);
return 0;
}
result:
%X: FFFFFF80, 80
I'm confused. How FFFFFF80
come. We know that char
type holds 1 byte. And I know that the difference between char
and unsigned char
is the way they treating highest bit , but both holds one byte.
And I don't think this program concerning any conversion process.
The sign bit will expand if type of c
is int
(convert unsigned char to int).But in this case, it's unsigned char
converting to char
, but both holds one byte.
So why the result of printf("%X",c)
contain 4 bytes?
Upvotes: 1
Views: 120
Reputation: 85316
printf
is a variadic function, it is defined as:
int printf(const char * fmt, ...);
That is, printf
does not know the types of arguments you passed to it, it relies on the format string to deduce the argument types.
Every argument after the format string is subject to integer promotions (char
is promoted to int
).
So what printf
receives in your case is a format string ("%%X: %X, %X\n"
), an int
containing -128
(because 0x80
represented as a char
on two's-complement architecture is -128
) and an int
containing 128
.
References:
ISO C § 6.3.1.1:
If an
int
can represent all values of the original type, the value is converted to anint
; otherwise, it is converted to anunsigned int
. These are called the integer promotions.
ISO C § 6.5.2.2:
If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type
float
are promoted todouble
. These are called the default argument promotions.The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.
P.S.
It is worth noting that the two's complement behavior you're experiencing is implementation-defined, i.e. (char)0x80
is not guaranteed to equal -128
on all platforms.
Upvotes: 2
Reputation:
As already commented, the answer is integer promotion, which is indeed a bit harder to understand:
integer promotion means that integer types smaller than int
are automatically converted to int
if int
can hold all values of the original integer type (obviously the case for char
, signed char
and unsigned char
) -- otherwise they're converted to unsigned int
.
integer promotion happens basically in two situations.
1) in arithmetic expressions:
signed char x = 40;
signed char y = 100;
unsigned char z = x + y; // <-- here, the addition is done with two ints
2) in function arguments if the argument is a variadic argument (like when calling printf
) or if the function doesn't have a prototype, IOW, if the argument type is not known.
char x = 'A';
printf("value: %d\n", x); // <-- here, x is passed as an int
So, the answer to your question is: for a signed char
, 0x80
is the representation of -128
. -128
as an int
is represented as 0xffffff80
.
Upvotes: 2