On my way to computing ranges of char, short, int, and long variables, both signed and unsigned, I took help of the following solutions:
According to solution 1, I expected (unsigned short)~0 in the code below to output -1 and 65535, assuming its behaviour is the same as (unsigned int)~0 code for the two format specifiers.
// the two statements below produce different results
printf("Value of unsigned int is %d\n", (unsigned int)~0); // outputs -1
printf("Value of unsigned int is %u\n", (unsigned int)~0); // outputs 4294967295
// whereas, the two statements below produce the same result. Why?
printf("Value of short unsigned int is %d\n", (unsigned short)~0); // outputs 65535, expected -1
printf("Value short unsigned int is %u\n", (unsigned short)~0); // outputs 65535
Why is there a difference in the behaviour of (unsigned short)~0 and (unsigned int)~0?
The behavior of those expressions is analogous. Supposing two's complement representation of type
int, each computes the largest representable value of its (unsigned) type.However, variable arguments to a variadic function such as
printfare subject to default argument promotions. This affectsunsigned short, promoting it tointifintcan represent allunsigned shortvalues, as is the case in your example (and tounsigned intotherwise). It does not affect arguments of typeintorunsigned int, or wider integer types.The key problem with the code presented is that ...
... exhibits undefined behavior on account of the
%ddirective not being correctly type matched to the corresponding argument.%dmust be matched to a signedint, but you have associated it with anunsigned int. In practice, the UB is manifesting as interpreting the bit pattern of the argument as if it were asignedintinstead of an unsigned one, but in principle, the program could have done anything at all within its power.Note well that this also has undefined behavior because of type mismatch:
The directive
%huwould be the best match to the corresponding actual argument, but%dis acceptable because of the aforementioned automatic type promotion.%udoes not match. In this case, however, the UB manifested is identical to the behavior you expected -- at least as far as the output indicates. In practice, the bit pattern of the non-negativesigned intargument has been interpreted as anunsigned int.