For the first case, change:
printf("%.2x", cx[i]);
to
printf("%.2x", cx[i] & 0xFF);
The plain char
type is signed, so 0xFF is sign-extended to an 8-byte value all F's, as shown in the printout.
The first number worked OK as all the bytes were in the range 0x00..0x7F, so that the value was not converted to a negative integer — it stayed positive. The second number didn't work out because one of the bytes was in the range 0x80..0xFF and so was converted to a negative integer. And the %.2x
will always print all the digits, but if there's only one, there'll be a 0 before that digit. The x
expects an unsigned int
.
With printf()
and other variadic functions, the arguments in the ...
part of the argument list are default promoted, so char
types (all varieties) are promoted to int
(as is short
), and float
is promoted to double
.
This is documented in the C standard (ISO/IEC 9899-2011):
6.5.2.2 Function calls
6 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. …
7 If the expression that denotes the called function has a type that does include a prototype,
the arguments are implicitly converted, as if by assignment, to the types of the
corresponding parameters, taking the type of each parameter to be the unqualified version
of its declared type. 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.
8 No other conversions are performed implicitly; in particular, the number and types of
arguments are not compared with those of the parameters in a function definition that
does not include a function prototype declarator.
Semi-tangential aside.
The rest of paragraph 6 includes:
If the function is defined with a type that includes a prototype, and
either the prototype ends with an ellipsis (, ...
) or …, the behavior is undefined.
That sentence has to be read in the context of 'If the expression that denotes the called function has a type that does not include a
prototype, …' at the beginning of the paragraph. It means that if you make a call to a function that is defined with ellipsis , ...
but there isn't a prototype in scope at the time of the call, the behaviour is undefined. You must make sure that you have a prototype in scope whenever you call a variadic function.