In c1 = 128;
, 128 does not fit in the signed eight-bit char
that your C implementation uses. 128 is converted to char
per C 2018 6.5.16.1 2: “the value of the right operand is converted to the type of the assignment expression…”
The conversion is implementation-defined, per 6.3.1.3 3: “Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.” Your C implementation converted 128, which is 100000002 as an unsigned binary numeral, to −128, which is represented with the same bits when using two’s complement for signed binary. Thus, the result is that c1
contains the value −128.
In printf("c1: %x, c2: %x\n", c1, c2);
, c1
is converted to an int
. This is because the rules for calling functions with ...
parameters are to apply the default argument promotions to the corresponding arguments, per 6.5.2.2 7: “The default argument promotions are performed on trailing arguments.”
The default argument promotions include the integer promotions, per 6.5.2.2 6. When the range of char
is narrower than int
, as it is in most C implementations, the integer promotions convert a char
to an int
, per 6.3.1.1 2: “If an int
can represent all values of the original type…, the value is converted to an int
…”
Thus, in printf("c1: %x, c2: %x\n", c1, c2);
, an int
value of −128 is passed as the second argument. Your C implementation uses 32-bit two’s complement for int
, in which −128 is represented with the bits 11111111111111111111111110000000, which we can express in hexadecimal as ffffff80.
The format string specifies a conversion using %x
. The proper argument type for %x
is unsigned int
. However, your C implementation has accepted the int
and reinterpreted its bits as an unsigned int
. Thus, the bits 11111111111111111111111110000000 are converted to the string “ffffff80”.
This explains why “ffffff80” is printed. It is not because c1
has four bytes but because it was converted to a four-byte type before being passed to printf
. Further, the conversion of a negative value to that four-byte type resulted in four bytes with many bits set.
Regarding c1 == c2
evaluating to true (1), this is simply because c1
was given the value −128 as explained above, and c2 = -128;
also assigns the value −128 to c2
, so c1
and c2
have the same value.