Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #402426 > unrolled thread
| Started by | highcrew <high.crew3868@fastmail.com> |
|---|---|
| First post | 2026-09-27 18:12 +0200 |
| Last post | 2026-09-30 13:05 -0700 |
| Articles | 6 — 6 participants |
Back to article view | Back to comp.lang.c
Dodging undefined behaviour in printf highcrew <high.crew3868@fastmail.com> - 2026-09-27 18:12 +0200
Re: Dodging undefined behaviour in printf Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-28 01:47 +0800
Re: Dodging undefined behaviour in printf Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-09-27 10:48 -0700
Re: Dodging undefined behaviour in printf James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-09-27 20:30 -0400
Re: Dodging undefined behaviour in printf David Brown <david.brown@hesbynett.no> - 2026-09-28 09:50 +0200
Re: Dodging undefined behaviour in printf "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-09-30 13:05 -0700
| From | highcrew <high.crew3868@fastmail.com> |
|---|---|
| Date | 2026-09-27 18:12 +0200 |
| Subject | Dodging undefined behaviour in printf |
| Message-ID | <119bf9d$1fk39$1@dont-email.me> |
Dear c.l.c.
I'm trying to refine my knowledge on the topic of type promotions, and
now I know how promotion is implied when passing arguments to a function
whose prototype is missing argument definition, or to functions having
variadic argument list.
So I was wondering about the following:
unsigned short x = value;
printf("%x", x);
Assuming that sizeof(unsigned short) < sizeof(int), I would guess that x
is promoted to signed int, which is however the wrong type, as it should
be unsigned int.
Well, it is is also true that the `int` value is not going to be
negative for sure.
Would this be a problem? Am I supposed to explicitly cast x to (unsigned
int) when passing it to printf?
I find it interesting that the problem is not a problem on architectures
where sizeof(unsigned short) == sizeof(unsigned int) -- if I will ever
find such a thing.
How about %hx then?
--
High Crew
[toc] | [next] | [standalone]
| From | Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> |
|---|---|
| Date | 2026-09-28 01:47 +0800 |
| Message-ID | <gFcuS.247783$4yM7.128897@fx08.ams4> |
| In reply to | #402426 |
On 9/28/2026 12:12 AM, highcrew wrote:
> Dear c.l.c.
>
> I'm trying to refine my knowledge on the topic of type promotions, and
> now I know how promotion is implied when passing arguments to a function
> whose prototype is missing argument definition, or to functions having
> variadic argument list.
>
> So I was wondering about the following:
>
> unsigned short x = value;
> printf("%x", x);
>
> Assuming that sizeof(unsigned short) < sizeof(int), I would guess that x
> is promoted to signed int, which is however the wrong type, as it should
> be unsigned int.
>
> Well, it is is also true that the `int` value is not going to be
> negative for sure.
>
> Would this be a problem? Am I supposed to explicitly cast x to (unsigned
> int) when passing it to printf?
>
> I find it interesting that the problem is not a problem on architectures
> where sizeof(unsigned short) == sizeof(unsigned int) -- if I will ever
> find such a thing.
>
> How about %hx then?
>
In my recollection, %hx is slightly better. And, even though I don't
like to thump the standard, my memory of it is somewhere along these
lines:
integer values smaller than int will be upconverted to int, because the
printf() is a variadic argument function.
integer values greater than int will /not/ be downconverted, but the
printf() has no automagic way to decide after the fact what the argu-
ment was supposed to be, so it's always best to use the right size
declaration in the format specifier, which is currently z for size_t.
So for instance, if you find a /big endian/ machine on an archaeological
dig, and wish to test its printf(), you're probably better off using the
right size format, since otherwise it might print the wrong end of the
int when you give it a short.
Now, I'm sure the other trolls on comp.lang.c will be happy to correct
all of the above, so I let them. They enjoy that kind of activity.
--
Johann | email: invalid -> com | http://www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | via Easynews.com
https://bsky.app/profile/myrkraverk.bsky.social | for ( ;; ) _:;
Federated at https://fed.brid.gy/bsky/myrkraverk.bsky.social
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-09-27 10:48 -0700 |
| Message-ID | <86v77qr3ez.fsf@linuxsc.com> |
| In reply to | #402426 |
highcrew <high.crew3868@fastmail.com> writes:
> Dear c.l.c.
>
> I'm trying to refine my knowledge on the topic of type promotions, and
> now I know how promotion is implied when passing arguments to a
> function whose prototype is missing argument definition, or to
> functions having variadic argument list.
>
> So I was wondering about the following:
>
> unsigned short x = value;
> printf("%x", x);
>
> Assuming that sizeof(unsigned short) < sizeof(int), I would guess that
> x is promoted to signed int, which is however the wrong type, as it
> should be unsigned int.
Yes, usually unsigned shorts are promoted to signed ints, although
the rule is expressed in terms of value ranges rather than sizes.
> Well, it is is also true that the `int` value is not going to be
> negative for sure.
>
> Would this be a problem? Am I supposed to explicitly cast x to
> (unsigned int) when passing it to printf?
The short answer is that just using 'x' works. No cast is
needed. For variadic arguments, corresponding signed and
unsigned types are interchangeable, as long as the argument
value is within the range of both types. The same rule applies
for arguments subject to the default promotions, if the function
being called is defined without a prototype.
> I find it interesting that the problem is not a problem on
> architectures where sizeof(unsigned short) == sizeof(unsigned int) --
> if I will ever find such a thing.
>
> How about %hx then?
How %hx works is the same as how %x works, except that whatever
value is sent (obtained as an unsigned int) is first converted
to unsigned short before formatting.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2026-09-27 20:30 -0400 |
| Message-ID | <119ccfu$1tfg6$1@dont-email.me> |
| In reply to | #402426 |
On 2026-09-27 12:12, highcrew wrote:
> Dear c.l.c.
>
> I'm trying to refine my knowledge on the topic of type promotions, and
> now I know how promotion is implied when passing arguments to a function
> whose prototype is missing argument definition, or to functions having
> variadic argument list.
"The ellipsis notation in a variadic function declarator (6.7.7.4)
causes argument type conversion to stop after the last declared
parameter, if present. The integer promotions are performed on each
trailing argument, and trailing arguments that have type float are
promoted to double. These are called the _default argument promotions_.
No other conversions are performed implicitly." (6.5.3.3p6)
The term "default argument promotions" is in italics, and ISO convention
indicating that the term is a special piece of jargon whose definition
is provided by that sentence.
> So I was wondering about the following:
>
> unsigned short x = value;
> printf("%x", x);
>
> Assuming that sizeof(unsigned short) < sizeof(int), I would guess that x
> is promoted to signed int, which is however the wrong type, as it should
> be unsigned int.
"If the original type is not a bit-precise integer type (6.2.5): if an
int can represent all values of the original type (as restricted by the
width, for a bit-field), the value is converted to an int;50) otherwise,
it is converted to an unsigned int. These are called the _integer
promotions_. All other types are unchanged by the integer promotions."
(6.3.2.1p2).
As before, this sentence serves as the official definition of the term
"integer promotions".
Note that what matters is not sizeof(), but the range of representable
values. It's a minor distinction, of importance mainly because the
standard allows types to have an arbitrarily large number of padding
bits. But the correct statement is that if USHRT_MAX < INT_MAX, the
value of x will be promoted to an int. Implementations are allowed to
have SHRT_MAX == INT_MAX, in which case USHRT_MAX > INT_MAX, in which
case x will remain unsigned short. Note that, in either case, the
promoted value will be the same as the original value.
"For signed types ... Each bit that is a value bit shall have the same
value as the same bit in the object representation of the corresponding
unsigned type." (6.2.6.2p2)
So the way in which the value is represented will be unchanged.
...> Would this be a problem? Am I supposed to explicitly cast x to
(unsigned
> int) when passing it to printf?
>
> I find it interesting that the problem is not a problem on architectures
> where sizeof(unsigned short) == sizeof(unsigned int) -- if I will ever
> find such a thing.
>
> How about %hx then?
%x is intended for unsigned int arguments, %hx expects the corresponding
argument to be unsigned short.
However,
"fprintf shall behave as if it uses va_arg with a type argument naming
the type resulting from applying the default argument promotions to the
type corresponding to the conversion specification and then converting
the result of the va_arg expansion to the type corresponding to the
conversion specification." (7.24.6.2p9)
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2026-09-28 09:50 +0200 |
| Message-ID | <119d683$23bo0$1@dont-email.me> |
| In reply to | #402426 |
On 27/09/2026 18:12, highcrew wrote:
> Dear c.l.c.
>
> I'm trying to refine my knowledge on the topic of type promotions, and
> now I know how promotion is implied when passing arguments to a function
> whose prototype is missing argument definition, or to functions having
> variadic argument list.
>
> So I was wondering about the following:
>
> unsigned short x = value;
> printf("%x", x);
>
> Assuming that sizeof(unsigned short) < sizeof(int), I would guess that x
> is promoted to signed int, which is however the wrong type, as it should
> be unsigned int.
>
> Well, it is is also true that the `int` value is not going to be
> negative for sure.
>
> Would this be a problem? Am I supposed to explicitly cast x to (unsigned
> int) when passing it to printf?
>
> I find it interesting that the problem is not a problem on architectures
> where sizeof(unsigned short) == sizeof(unsigned int) -- if I will ever
> find such a thing.
(There are plenty of such architectures - basically, all 8-bit and
16-bit microcontrollers. Those are less popular now than they used to
be, as 32-bit ARM dominates for new devices, but there are no shortages
of designs with 16-bit int. For amateurs, the most common such platform
is the Arduino.)
>
> How about %hx then?
>
Many people, myself included, like to use the "-Wformat" warning in gcc
(and clang) - it is part of the "-Wall" warning settings, or can be
enabled or disabled explicitly. In printf calls where the format string
is visible to the compiler, typically as a string literal, the compiler
will check that the format specifiers and the actual arguments match up
correctly in type. The checks are fairly fussy, and will give you a
warning if types don't match up - even if they would work in practice.
For example, the warning triggers for mismatches between "int" and "long
int" even on platforms where they are the same size and in practice
would generally work fine. But it takes into account the default
argument promotions (described by other posters).
Checks and warnings from the compiler are not a substitute for knowing
the rules, but they are a very handy extra check.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2026-09-30 13:05 -0700 |
| Message-ID | <119jq22$igr0$1@dont-email.me> |
| In reply to | #402426 |
On 9/27/2026 9:12 AM, highcrew wrote:
> Dear c.l.c.
>
> I'm trying to refine my knowledge on the topic of type promotions, and
> now I know how promotion is implied when passing arguments to a function
> whose prototype is missing argument definition, or to functions having
> variadic argument list.
>
> So I was wondering about the following:
>
> unsigned short x = value;
> printf("%x", x);
>
> Assuming that sizeof(unsigned short) < sizeof(int), I would guess that x
> is promoted to signed int, which is however the wrong type, as it should
> be unsigned int.
>
> Well, it is is also true that the `int` value is not going to be
> negative for sure.
>
> Would this be a problem? Am I supposed to explicitly cast x to (unsigned
> int) when passing it to printf?
>
> I find it interesting that the problem is not a problem on architectures
> where sizeof(unsigned short) == sizeof(unsigned int) -- if I will ever
> find such a thing.
>
> How about %hx then?
>
Remember to cast to (void*) wrt a %p.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web