Print a short instead of an int... ? What's up with "%hd"?

M

Martin Wells

When passing arguments to a VAL function, all integer types are
promoted, and floats become doubles. Therefore, signed short will be
promoted to signed int. Therefore I can't see any reason why you'd
have:

printf( "%hd", my_short);

instead of:

printf( "%d", my_short);


Martin
 
J

James Kuyper Jr.

Martin said:
When passing arguments to a VAL function, all integer types are
promoted, and floats become doubles. Therefore, signed short will be
promoted to signed int. Therefore I can't see any reason why you'd
have:

printf( "%hd", my_short);

instead of:

printf( "%d", my_short);

I believe that the purpose is to allow the use of the same format string
for printf() and scanf(). The 'h' adds nothing during the printing
process, but makes a difference in the scanning process.
 
K

Kenneth Brody

James Kuyper Jr. said:
I believe that the purpose is to allow the use of the same format string
for printf() and scanf(). The 'h' adds nothing during the printing
process, but makes a difference in the scanning process.

It could make a difference. Consider "%hx" when passed (short)-1,
which on my system prints "ffff", whereas "%x" prints "ffffffff".

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
M

Martin Wells

Kenneth:
It could make a difference. Consider "%hx" when passed (short)-1,
which on my system prints "ffff", whereas "%x" prints "ffffffff".


OK I can see how the following are true:

(unsigned)(short)-1 == UINT_MAX (maybe 0xffff)
(short unsigned)(short)-1 == USHRT_MAX (maybe 0xffffffff)

....but is it not undefined behaviour to supply printf with a signed
integer type when it expects an unsigned integer type, or vice versa?

If I wanted to print the max value of an unsigned short (without using
USHRT_MAX of course), then I'd go with:

printf("%u",(unsigned)(short unsigned)-1)

Martin
 
O

Old Wolf

It could make a difference. Consider "%hx" when passed (short)-1,
which on my system prints "ffff", whereas "%x" prints "ffffffff".

Well, you caused undefined behaviour by passing a
signed value. James' comment should be read as saying
it makes no difference to conforming code!

The %hx could in theory allow the compiler to optimize
more, as the printf implementation has the option of
discarding 2 of the 4 bytes read (say) before processing
them.
 
K

Kenneth Brody

Old said:
Well, you caused undefined behaviour by passing a
signed value. James' comment should be read as saying
it makes no difference to conforming code!

You are, of course, correct. I hadn't thought about it before,
but it makes perfect sense that %x takes an unsigned value.
(After all, I would want something like "8000" to display, and
not "-7fff".)
The %hx could in theory allow the compiler to optimize
more, as the printf implementation has the option of
discarding 2 of the 4 bytes read (say) before processing
them.

What does the standard say about a varadic function which gets
passed an int but reads it as short? Given that the standard
requires that (in this instance) a short be promoted to int
anyway, does passing an int invoke UB?

On a system with 16-bit short and 32-bit int, does this invoke
UB?

printf("%hd\n",65536);

My system displays zero, but "gives you the output you expect"
is allowed under UB. :)

Section 7.19.6.1p7 seems to allow it:

h Specifies that a following d, i, o, u, x, or X conversion
specifier applies to a short int or unsigned short int
argument (the argument will have been promoted according
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
to the integer promotions, but its value shall be
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
converted to short int or unsigned short int before
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
printing); or that a following n conversion specifier
^^^^^^^^
applies to a pointer to a short int argument.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
O

Old Wolf

On a system with 16-bit short and 32-bit int, does this invoke
UB?

printf("%hd\n",65536);

I would think so, but a more interesting question
is whether this invokes UB:
printf("%hd\n", 0);

We've had this discussion at least once before (in
fact, I initiated it one time). I don't recall the
conclusion however :)
 
D

Dik T. Winter

>
> Well, you caused undefined behaviour by passing a
> signed value. James' comment should be read as saying
> it makes no difference to conforming code!

Yes, even (unsigned short)2 passed for "%hx" causes undefined behaviour,
when int and short are not essentially the same. So when passing
an "unsigned short", you should cast it to an "unsigned int". Ah, I
like those integer promotion rules. The only arguments types you can
reliably pass to "%x" are unsigned int and longer.
 
P

pete

Dik said:
The only arguments types you can
reliably pass to "%x" are unsigned int and longer.

What is reliable about using a longer type than unsigned,
with "%x"?
 
C

Charlie Gordon

Dik T. Winter said:
Yes, even (unsigned short)2 passed for "%hx" causes undefined behaviour,
when int and short are not essentially the same. So when passing
an "unsigned short", you should cast it to an "unsigned int". Ah, I
like those integer promotion rules. The only arguments types you can
reliably pass to "%x" are unsigned int and longer.

It may well be the case under the current wording of the standard, but I
cannot believe it be the intent of the Commitee. It would take an
inordinate amount of bad faith to come up with an implementation that shows
unexpected behaviour for such a case. It would cause enough portability
problems for so many programs to be adequately qualified as *broken*. There
is nothing wrong with passing an int or shorter type for %x format. Passing
anything larger (or longer) is wrong.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

It may well be the case under the current wording of the standard, but I
cannot believe it be the intent of the Commitee.

That's not what the current wording of the standard says, and like you I
would be extremely surprised if it actually turned out to be the intent.
%hx accepts an argument of whatever type unsigned short promotes to. This
will be signed int on some implementations, and unsigned on others, but
(unsigned short)2 will be a valid argument on all implementations.
 
D

Dik T. Winter

....
> That's not what the current wording of the standard says, and like you I
> would be extremely surprised if it actually turned out to be the intent.
> %hx accepts an argument of whatever type unsigned short promotes to.

In the draft version of the standard I have, section 7.19.6.1, par 3:
o,u,x,X The *unsigned int* argument is converted to unsigned octal (o),
...
 
J

Justin Spahr-Summers

In the draft version of the standard I have, section 7.19.6.1, par 3:
o,u,x,X The *unsigned int* argument is converted to unsigned octal (o),
...

h Specifies that a following d, i, o, u, x, or X conversion
specifier
applies to a short int or unsigned short int argument (the
argument
will have been promoted according to the integer promotions,
but its
value shall be converted to a short int or unsigned short int
before
printing)
 
J

Justin Spahr-Summers

h Specifies that a following d, i, o, u, x, or X conversion
specifier
applies to a short int or unsigned short int argument (the
argument
will have been promoted according to the integer promotions,
but its
value shall be converted to a short int or unsigned short int
before
printing)

Ick. I thought I wrapped it to the right length. Apparently not.
 
C

CBFalconer

Dik T. Winter said:
.... snip ...


In the draft version of the standard I have, section 7.19.6.1, par 3:
o,u,x,X The *unsigned int* argument is converted to unsigned octal
(o), ...

I think you meant para. 8.
 
P

pete

In the draft version of the standard I have, section 7.19.6.1, par 3:
o,u,x,X The *unsigned int*
argument is converted to unsigned octal (o), ...

I still don't see where you're getting "and longer" from.
 
D

Dik T. Winter

>
> h Specifies that a following d, i, o, u, x, or X conversion specifier
> applies to a short int or unsigned short int argument (the argument
> will have been promoted according to the integer promotions, but its
> value shall be converted to a short int or unsigned short int before
> printing)

Indeed. But what is the 'x' doing if the argument is a signed int?
Suppose we have: %hd and (unsigned short)2 as argument. The argument is
promoted to int. 'h' specifies that the argument was short or unsigned
short before promotion, and that the argument will be converted to short
or unsigned short (to what? how does printf know whether the actual argument
was a short or an unsigned short before promotion?). But now 'x' does not
specify what is happening, because it only specifies what is happening when
the argument after promotion is an unsigned int. BTW, this means that also
%lx is actually undefined.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,785
Messages
2,569,624
Members
45,318
Latest member
LuisWestma

Latest Threads

Top