Connecting Tech Pros Worldwide Help | Site Map

printf length modifier

Spoon
Guest
 
Posts: n/a
#1: Apr 26 '07
Hello,

Does the following code invoke undefined behavior?

#include <stdio.h>
int main(void)
{
unsigned short int u = 42;
printf("%u\n", u);
return 0;
}

gcc doesn't seem to mind.
$ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
$ ./a.out
42

Is it mandatory to add the 'h' length modifier in the format string?

unsigned short int u = 42;
printf("%hu\n", u);

Regards.
CBFalconer
Guest
 
Posts: n/a
#2: Apr 26 '07

re: printf length modifier


Spoon wrote:
Quote:
>
Does the following code invoke undefined behavior?
>
#include <stdio.h>
int main(void)
{
unsigned short int u = 42;
printf("%u\n", u);
return 0;
}
Yes.
Quote:
>
gcc doesn't seem to mind.
$ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
$ ./a.out
42
>
Is it mandatory to add the 'h' length modifier in the format string?
Yes. Add the -O (capital letter) option to the gcc run.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>
cbfalconer at maineline.net


--
Posted via a free Usenet account from http://www.teranews.com

Spoon
Guest
 
Posts: n/a
#3: Apr 26 '07

re: printf length modifier


CBFalconer wrote:
Quote:
Spoon wrote:
Quote:
>Does the following code invoke undefined behavior?
>>
>#include <stdio.h>
>int main(void)
>{
> unsigned short int u = 42;
> printf("%u\n", u);
> return 0;
>}
>
Yes.
>
Quote:
>gcc doesn't seem to mind.
>$ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
>$ ./a.out
>42
>>
>Is it mandatory to add the 'h' length modifier in the format string?
>
Yes. Add the -O (capital letter) option to the gcc run.
$ gcc -O -Wall -Wextra -std=c89 -pedantic zzz.c
$ ./a.out
42

$ gcc -O3 -Wall -Wextra -std=c89 -pedantic zzz.c
$ ./a.out
42

:-)

Aren't short int parameters "widened" to int in variadic function calls?

Regards.
Flash Gordon
Guest
 
Posts: n/a
#4: Apr 26 '07

re: printf length modifier


Spoon wrote, On 26/04/07 10:33:
Quote:
Hello,
>
Does the following code invoke undefined behavior?
>
#include <stdio.h>
int main(void)
{
unsigned short int u = 42;
printf("%u\n", u);
return 0;
}
<snip>
Quote:
Is it mandatory to add the 'h' length modifier in the format string?
>
unsigned short int u = 42;
printf("%hu\n", u);
unsigned short is likely to be promoted to int rather than signed int,
so using %u is lying. Anyway, why would you want to use a possibly
incorrect format specifier when you know the definitely correct one?
--
Flash Gordon
Flash Gordon
Guest
 
Posts: n/a
#5: Apr 26 '07

re: printf length modifier


Spoon wrote, On 26/04/07 12:20:
Quote:
CBFalconer wrote:
Quote:
>Spoon wrote:
Quote:
>>Does the following code invoke undefined behavior?
>>>
>>#include <stdio.h>
>>int main(void)
>>{
>> unsigned short int u = 42;
>> printf("%u\n", u);
>> return 0;
>>}
>>
>Yes.
<snip>
Quote:
Quote:
Quote:
>>Is it mandatory to add the 'h' length modifier in the format string?
>>
>Yes. Add the -O (capital letter) option to the gcc run.
<snip>
Quote:
Aren't short int parameters "widened" to int in variadic function calls?
You are using unsigned short, which could be widened to int (most
probable) or unsigned int, and using the format specifier for an
unsigned int. int and unsigned int are NOT the same thing.

There is also the big question of why you do not want to use what you
know is definitely the correct format specifier.
--
Flash Gordon
Spoon
Guest
 
Posts: n/a
#6: Apr 26 '07

re: printf length modifier


Flash Gordon wrote:
Quote:
Spoon wrote, On 26/04/07 12:20:
Quote:
>CBFalconer wrote:
Quote:
>>Spoon wrote:
>>>Does the following code invoke undefined behavior?
>>>>
>>>#include <stdio.h>
>>>int main(void)
>>>{
>>> unsigned short int u = 42;
>>> printf("%u\n", u);
>>> return 0;
>>>}
>>>
>>Yes.
>
<snip>
>
Quote:
Quote:
>>>Is it mandatory to add the 'h' length modifier in the format string?
>>>
>>Yes. Add the -O (capital letter) option to the gcc run.
>
<snip>
>
Quote:
>Aren't short int parameters "widened" to int in variadic function calls?
>
You are using unsigned short, which could be widened to int (most
probable) or unsigned int, and using the format specifier for an
unsigned int. int and unsigned int are NOT the same thing.
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
equivalent because both conversions are well-defined.
Quote:
There is also the big question of why you do not want to use what you
know is definitely the correct format specifier.
u is, in fact, an uint16_t and I don't know for sure that u is an
unsigned short int. It might be an unsigned int.

Regards.
Flash Gordon
Guest
 
Posts: n/a
#7: Apr 26 '07

re: printf length modifier


Spoon wrote, On 26/04/07 14:31:
Quote:
Flash Gordon wrote:
Quote:
>Spoon wrote, On 26/04/07 12:20:
Quote:
>>CBFalconer wrote:
>>>Spoon wrote:
>>>>Does the following code invoke undefined behavior?
>>>>>
>>>>#include <stdio.h>
>>>>int main(void)
>>>>{
>>>> unsigned short int u = 42;
>>>> printf("%u\n", u);
>>>> return 0;
>>>>}
>>>>
>>>Yes.
>>
><snip>
>>
Quote:
>>>>Is it mandatory to add the 'h' length modifier in the format string?
>>>>
>>>Yes. Add the -O (capital letter) option to the gcc run.
>>
><snip>
>>
Quote:
>>Aren't short int parameters "widened" to int in variadic function calls?
>>
>You are using unsigned short, which could be widened to int (most
>probable) or unsigned int, and using the format specifier for an
>unsigned int. int and unsigned int are NOT the same thing.
>
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
equivalent because both conversions are well-defined.
True, but it is reasonable to assume that in the real code other values
will be used. It is not unreasonable to expect that some of those values
will be too large to fit in a signed short, or why bother with the extra
typing?
Quote:
Quote:
>There is also the big question of why you do not want to use what you
>know is definitely the correct format specifier.
>
u is, in fact, an uint16_t and I don't know for sure that u is an
unsigned short int. It might be an unsigned int.
If this is C99 code then I believe there is a macro provided in C99 to
solve this problem. Otherwise, cast the value to a known type for printing.
printf("%u\n", (unsigned int)u);
Or, alternatively, as you know that any value that will fit in an
unsigned 16 bit integer will fit in an unsigned short (which may be more
than 16 bits, but not less), cast to unsigned short and use the h modifier.
--
Flash Gordon
=?utf-8?B?SGFyYWxkIHZhbiBExLNr?=
Guest
 
Posts: n/a
#8: Apr 26 '07

re: printf length modifier


Spoon wrote:
Quote:
Flash Gordon wrote:
Quote:
Spoon wrote, On 26/04/07 12:20:
Quote:
CBFalconer wrote:
>Spoon wrote:
>>Does the following code invoke undefined behavior?
>>>
>>#include <stdio.h>
>>int main(void)
>>{
>> unsigned short int u = 42;
>> printf("%u\n", u);
>> return 0;
>>}
>>
>Yes.
<snip>
Quote:
>>Is it mandatory to add the 'h' length modifier in the format string?
>>
>Yes. Add the -O (capital letter) option to the gcc run.
<snip>
Quote:
Aren't short int parameters "widened" to int in variadic function calls?
You are using unsigned short, which could be widened to int (most
probable) or unsigned int, and using the format specifier for an
unsigned int. int and unsigned int are NOT the same thing.
>
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
equivalent because both conversions are well-defined.
Huh? I really don't understand what you're trying to say here. Could
you please explain?
Quote:
Quote:
There is also the big question of why you do not want to use what you
know is definitely the correct format specifier.
>
u is, in fact, an uint16_t and I don't know for sure that u is an
unsigned short int. It might be an unsigned int.
The format specifier for uint16_t is PRIu16.

#include <stdio.h>
#include <inttypes.h>

#ifndef UINT16_MAX
#error uint16_t not supported
#endif

int main(void)
{
uint16_t u = 42;
printf("%" PRIu16 "\n", u);
return 0;
}

Flash Gordon
Guest
 
Posts: n/a
#9: Apr 26 '07

re: printf length modifier


Harald van Dijk wrote, On 26/04/07 18:51:
Quote:
Spoon wrote:
<snip>
Quote:
Quote:
>(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
>equivalent because both conversions are well-defined.
>
Huh? I really don't understand what you're trying to say here. Could
you please explain?
The standard guarantees that the representation of all positive values
of int is the same as the representation of those values in an unsigned
int. At least, I assume that is what Spoon meant, although if so it
could be phrased better.
--
Flash Gordon
=?utf-8?B?SGFyYWxkIHZhbiBExLNr?=
Guest
 
Posts: n/a
#10: Apr 26 '07

re: printf length modifier


Flash Gordon wrote:
Quote:
Harald van Dijk wrote, On 26/04/07 18:51:
Quote:
Spoon wrote:
>
<snip>
>
Quote:
Quote:
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
equivalent because both conversions are well-defined.
Huh? I really don't understand what you're trying to say here. Could
you please explain?
>
The standard guarantees that the representation of all positive values
of int is the same as the representation of those values in an unsigned
int. At least, I assume that is what Spoon meant, although if so it
could be phrased better.
Thanks for the explanation. I don't think there's any prohibition
against an implementation passing the object type along with the
value, and bombing out if the passed type does not exactly match the
expected type for printf(), but only bombing out if the passed type
does not loosely match the expected type for va_arg(). Aside from an
extremely strict debugging implementation though, I can't imagine why
anyone would want to do that.

Keith Thompson
Guest
 
Posts: n/a
#11: Apr 26 '07

re: printf length modifier


Spoon <devnull@localhost.comwrites:
Quote:
Flash Gordon wrote:
Quote:
>Spoon wrote, On 26/04/07 12:20:
Quote:
>>CBFalconer wrote:
>>>Spoon wrote:
>>>>Does the following code invoke undefined behavior?
>>>>>
>>>>#include <stdio.h>
>>>>int main(void)
>>>>{
>>>> unsigned short int u = 42;
>>>> printf("%u\n", u);
>>>> return 0;
>>>>}
>>>>
>>>Yes.
><snip>
>>
Quote:
>>>>Is it mandatory to add the 'h' length modifier in the format string?
>>>>
>>>Yes. Add the -O (capital letter) option to the gcc run.
><snip>
>>
Quote:
>>Aren't short int parameters "widened" to int in variadic function calls?
>You are using unsigned short, which could be widened to int (most
>probable) or unsigned int, and using the format specifier for an
>unsigned int. int and unsigned int are NOT the same thing.
>
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int
are equivalent because both conversions are well-defined.
Conversion has nothing to do with it. Conversion between int and
double is well-defined, but passing a double argument for a "%d"
format invokes undefined behavior. No conversion, other than argument
promotions, occurs for variadic arguments.

It's true that the value 42 is guaranteed to have the same
*representation* in types int and unsigned int. Specifically, C99
6.2.5p9 says:

The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same.

with a footnote:

The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions, return values
from functions, and members of unions.

So you can look carefully through the standard for proof that the code
will work properly whether the argument is promoted to int or to
unsigned int (note that this depends on a footnote, which is
nonnormative). Note that you'll also need to depend on the
implementer getting this right. It's also likely that the argument
will be promoted to int on all the platforms you use, so you'll never
have a chance to test the case where it's promoted to unsigned int,
just in case you missed something.

Or you can write simpler code that doesn't depend on a potentially
shaky line of reasoning.
Quote:
Quote:
>There is also the big question of why you do not want to use what
>you know is definitely the correct format specifier.
>
u is, in fact, an uint16_t and I don't know for sure that u is an
unsigned short int. It might be an unsigned int.
So convert it to unsigned int and use "%u".

Incidentally, there's another subtle issue here. The standard's
description of printf() describes the required formats for various
types. It's almost certainly safe to assume that printf() uses the
same mechanisms as a user-written variadic function, so you can safely
assume that argument promotion occurs as you would expect. But the
standard doesn't *quite* come out and say so. (There was a lengthy
discussion of this in comp.std.c a while ago.) I don't think it's
anything to worry about, but it's enough to make me more cautious with
format strings than I absolutely need to be.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jack Klein
Guest
 
Posts: n/a
#12: Apr 27 '07

re: printf length modifier


On 26 Apr 2007 13:29:45 -0700, Harald van D?k <truedfx@gmail.com>
wrote in comp.lang.c:
Quote:
Flash Gordon wrote:
Quote:
Harald van D?k wrote, On 26/04/07 18:51:
Quote:
Spoon wrote:
<snip>
Quote:
>(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
>equivalent because both conversions are well-defined.
>
Huh? I really don't understand what you're trying to say here. Could
you please explain?
The standard guarantees that the representation of all positive values
of int is the same as the representation of those values in an unsigned
int. At least, I assume that is what Spoon meant, although if so it
could be phrased better.
>
Thanks for the explanation. I don't think there's any prohibition
against an implementation passing the object type along with the
value, and bombing out if the passed type does not exactly match the
expected type for printf(), but only bombing out if the passed type
does not loosely match the expected type for va_arg(). Aside from an
extremely strict debugging implementation though, I can't imagine why
anyone would want to do that.
Actually there is such a prohibition, 6.5.2.2 p6. It applies to both
functions without prototypes and to the variable arguments of variadic
functions:

<begin>
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. If the
number of arguments does not equal the number of parameters, the
behavior is undefined. If the function is defined with a type that
includes a prototype, and either the prototype ends with an ellipsis
(, ...) or the types of the arguments after promotion are not
compatible with the types of the parameters, the behavior is
undefined. If the function is defined with a type that does not
include a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:

— one promoted type is a signed integer type, the other promoted type
is the corresponding unsigned integer type, and the value is
representable in both types;

— both types are pointers to qualified or unqualified versions of a
character type or void.
<end>

So it makes no difference if the unsigned short is promoted to signed
or unsigned int, the actual int object has exactly the same bit
representation and is passed the same way.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
=?utf-8?B?SGFyYWxkIHZhbiBExLNr?=
Guest
 
Posts: n/a
#13: Apr 27 '07

re: printf length modifier


Jack Klein wrote:
Quote:
On 26 Apr 2007 13:29:45 -0700, Harald van D?k <truedfx@gmail.com>
wrote in comp.lang.c:
>
Quote:
Flash Gordon wrote:
Quote:
Harald van D?k wrote, On 26/04/07 18:51:
Spoon wrote:
>
<snip>
>
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
equivalent because both conversions are well-defined.

Huh? I really don't understand what you're trying to say here. Could
you please explain?
>
The standard guarantees that the representation of all positive values
of int is the same as the representation of those values in an unsigned
int. At least, I assume that is what Spoon meant, although if so it
could be phrased better.
Thanks for the explanation. I don't think there's any prohibition
against an implementation passing the object type along with the
value, and bombing out if the passed type does not exactly match the
expected type for printf(), but only bombing out if the passed type
does not loosely match the expected type for va_arg(). Aside from an
extremely strict debugging implementation though, I can't imagine why
anyone would want to do that.
>
Actually there is such a prohibition, 6.5.2.2 p6.
6.5.2.2p6 describes function calls where the function declaration
lacks a prototype. Any definition of printf must include a prototype.
6.5.2.2p7 describes function calls where the function declaration
includes a prototype, and contains no exception similar to what you
quoted.

Closed Thread


Similar C / C++ bytes