0

Consider the following:

unsigned int  i1 = 0xFFFFFFFF;
unsigned char c1 = i1;
char          c2 = i1;

printf("%x\n", i1);       // 0xFFFFFFFF as expected
printf("%x\n", c1);       // 0xFF as expected
printf("%x\n", c2);       // 0xFFFFFFFF ????
printf("%d\n", c1 == c2); // false ????

I know, one should not assign an int to a char. Anyway, look how c2 seems to be storing more than a byte. What I expected was a copy of the "less significant byte" of n1 into c2. Am I wrong to assume this? Is there no copy at all? Why does the behavior of unsigned char differs from char?


I actually found this in a very concrete situation while using gethostbyname(). It returns a struct which contains a field char *h_addr storing an ipv4 address (four 8 bit long numbers). I wanted to print the ip address as numbers but got abnormally large results.


I know a workaround, masking with i1 & 0xFF works but I would like to understand the issue.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • What are n1, n2, and n3? I see i1 (not n1). – franji1 Jan 29 '21 at 19:18
  • When passed to `printf` `char` is getting converted to `int`. – Eugene Sh. Jan 29 '21 at 19:19
  • You learned to be very, very careful when mixing signed and unsigned values. I suspect if you enable all compiler warnings, you'll get a good number of them. – Andrew Henle Jan 29 '21 at 19:24
  • "I know, one should not assign an int to a char" - more things to unlearn. You do this all the time – Antti Haapala -- Слава Україні Jan 29 '21 at 20:02
  • @AnttiHaapala: The wording here is unclear. It is okay *per se* to assign an `int` type to a `char`, but it is not generally okay to assign an `int` value to a `char` if it may be outside the values representable in a `char`, as it is not portable (is not fully defined by the C standard, does not yield strictly conforming code, and could trap). – Eric Postpischil Jan 29 '21 at 20:05

1 Answers1

1

In your system the type char behaves as the type signed char.

After this assignment

char          c2 = n1;

Note: It seems there is a typo and you mean

char          c2 = i1;

the variable c2 has the value 0xff that is -1.

In this call

printf("%x\n", c2);

the argument expression c2 is converted to the type int propagating the sign bit due to the integer promotions. And this value is outputted according to the format %x.

Pay attention to that you need to write

printf( "%x\n",( unsigned int ) c2 );

because the conversion specifier x expects an object of the type unsigned int.

If you want to get the expected by you result you need output the objects as objects of character types using conversion modifier hh. For example

#include <stdio.h>

int main(void) 
{
    unsigned int  i1 = 0xFFFFFFFF;
    unsigned char c1 = n1;
    char          c2 = n1;

    printf( "%x\n", i1 );
    printf( "%hhx\n", c1 );
    printf( "%hhx\n", c2 );
}

The program output is

ffffffff
ff
ff

Also it seems you made a typo and wrote

printf("%d\n", n3 == n2);

instead of

printf("%d\n", c1 == c2);

If so then again the operands of the comparison operator are implicitly converted to the type int due to the integer promotions. As the operand c1 has the type unsigned char then it is converted to the value 0x000000FF while the operand c2 as it stores a negative value is converted to the value 0xFFFFFFFF. So the result values are not equal to each other.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335