MMMMMCCLXXVII
MMMMMCCLXXVII

Reputation: 581

printf char type in base16 with confused phenomenon

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

Answers (2)

rustyx
rustyx

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 an int; otherwise, it is converted to an unsigned 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 to double. 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

user2371524
user2371524

Reputation:

As already commented, the answer is integer promotion, which is indeed a bit harder to understand:

1. what is it:

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.

2. when does it happen:

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

Related Questions