hh Specifies that a following d, i, o, u, x, or X
conversion specifier applies to a signed char
or unsigned char argument (the argument will
have been promoted according to the integer
promotions, but its value shall be converted to
signed char or unsigned char before printing);
or that a following n conversion specifier
applies to a pointer to a signed char argument.
with similar wording for "h".
Suppose CHAR_BIT is 8. Consider the following program:
#include <stdio.h>
int
main(void)
{
printf("%hhu\n", 257);
}
The argument 257 has type int which is the correct type from promotion
of unsigned char, but the value 257 could not have arisen from passing
an unsigned char argument. Is the implementation required to convert
the value 257 to unsigned char and print 1, or is the behavior
undefined?
--
Joseph S. Myers
js...@cam.ac.uk
I would take the view that the implementation is required to convert it
to unsigned char (which in this case involves reduction modulo 256). Had
you put %hhd it would be implementation-defined (since the conversion
is) or a signal is raised.
--
Clive D.W. Feather | Internet Expert | Work: <cl...@demon.net>
Tel: +44 20 8371 1138 | Demon Internet | Home: <cl...@davros.org>
Fax: +44 20 8371 1037 | Thus plc | Web: <http://www.davros.org>
Written on my laptop; please observe the Reply-To address
Another interpretation is that the program is not s.c. since it did
not provide an unsigned char argument.
7.9.16.3:
"Synopsis
#include <stdio.h>
int printf(const char * restrict format, ...);
"
Therefore, 6.5.2.3p7 applies to the printf() call:
"If the expression that denotes the called function has a type that does
include a prototype ... 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."
as is also suggested by 7.9.16.1p7 (describing fprintf(), but inherited
by the description of printf()):
"the argument will have been promoted according to the integer
promotions, but its value shall be converted to signed char or unsigned
char before printing"
According to 7.1.4p1, when using standard library functions:
"If an argument to a function has ... a type (after promotion) not
expected by a function with variable number of arguments, the behavior
is undefined."
I don't see how a conforming implementation would be allowed to
distinguish between a printf() argument that gets promoted in accordance
with the rules for a function with a variable number of arguments, and
an argument that was already of the promoted type.
There is more to it than type; there is also value. The spec for
hh says that the argument shall be of type char or unsigned char,
which imposes a requirement on the range of values. If a program
does not provide a char but rather an int, it has invoked
undefined behavior *even when the value happens to lie within the
valid range for a char*. Obviously the implementation will work
anyway in such a case, since within the fprintf implementation it
has exactly the same argument either way; however, it might *not*
work when the value exceeds that possible for a char, since the
fprintf implementation is allowed to assume that the program has
followed the specification. My advice is to pass a char when a
char is required -- why else would you be using hh?