This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Re: Regression with printf 8-bit format macros
- From: Ambroz Bizjak <ambrop7 at gmail dot com>
- To: Craig Howland <howland at lgsinnovations dot com>
- Cc: newlib at sourceware dot org
- Date: Mon, 4 Jan 2016 20:16:05 +0100
- Subject: Re: Regression with printf 8-bit format macros
- Authentication-results: sourceware.org; auth=none
- References: <CAOA3yK+__aWFL8KHUUEuPYGNCjAsXBeRDKpgWQEzYj3YrXNOxA at mail dot gmail dot com> <2655776 dot nuc1R7VGlh at infernus> <CAOA3yK+k8m1ub30X4ngjYhtEHg5L4bEQLFZPKwCYRhCMQjK86g at mail dot gmail dot com> <568A55D7 dot 1080107 at foss dot arm dot com> <CAOA3yKJOzTtjh4AtK6B7_tprYkzUeScinEyYh5P_ieNOxsFN-w at mail dot gmail dot com> <568AB4D4 dot 2070906 at LGSInnovations dot com>
Hi Chris, others,
The quoted part of the standard does explain how "hh" shall behave,
but I do not see any implication that PRI*N should use hh or generally
that the described conversion (after promotion) is required for PRI*N.
(note: I suspect you meant to use PRIu8 in the example not PRId8
because the conversion of 1000 to int8_t is an integer overflow.)
About the %n issue, it has no relation to the PRI* macros. The PRI*
macros cannot possibly used together with "n", because each PRI* macro
must end with a conversion specifier, which is not "n", and there can
only be one conversion specifier in a conversion. For example,
"%n"PRId8 and "%"PRId8"n" could become "%nd" and "%dn" respectively
(the first one writes out the position then prints a literal d, the
second prints a integer and a literal n). Notice that the standard
does not define any "PRIn..." macro.
Best regards,
Ambroz
On Mon, Jan 4, 2016 at 7:07 PM, Craig Howland
<howland@lgsinnovations.com> wrote:
> On 01/04/2016 11:05 AM, Ambroz Bizjak wrote:
>>
>> Hi Andre,
>>
>> I understand that defining PRI*8 to "*" rather than "hh*" is not
>> elegant, but it is correct.
>>
>> This is the relevant text from the C99 draft (7.8.1):
>>
>> Each of the following object-like macros expands to a character string
>> literal containing a conversion specifier, possibly modified by a
>> length modifier, suitable for use within the format argument of a
>> formatted input/output function when converting the corresponding
>> integer type. These macro names have the general form of PRI
>> (character string literals for the fprintf and fwprintf family) or SCN
>> (character string literals for the fscanf and fwscanf family),
>> followed by the conversion specifier, followed by a name corresponding
>> to a similar type name in 7.18.1. In these names, N represents the
>> width of the type as described in 7.18.1. For example, PRIdFAST32 can
>> be used in a format string to print the value of an integer of type
>> int_fast32_t.
>>
>> So all that is required is that the definition is suitable for use in
>> combination with that type. There is nothing that specifically implies
>> that PRI*8 needs to be "hh*".
>
> Well, actually there is, but it is "hidden" in the fprintf hh definition:
> "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."
> There are actually 2 reasons why it must contain "hh".
> Firstly then, according to the standard (the part in parentheses),
> printf("%"PRId8, 1000) really should print 232--1000 is not OK (as suggested
> in the first email in this chain) because the passed value gets converted
> before printing.
> Secondly, it also makes a difference for %n--it is critical that the pointer
> is to char and not int. (While you might think that %n is really a
> scan--rather than a print--specification, the standard is explicit (as
> quoted above by Ambroz) that the PRI* macros go with the fprintf family and
> SCN* with the scanf family. While this is probably an oversight/mistake in
> the standard (i.e. SCN* really should go with printf's %n), that is what it
> does say. I also checked C11, and they did not change the language
> concerning this.).
>>
>>
>> For example, if PRId8 is defined to "d", the following code will
>> behave as expected. This is because x is implicitly promoted to int,
>> and int is the valid type to use with %d.
>> uint8_t x = 255; printf("%"PRId8, x);
>>
>> I think that one of these three things should be done:
>> - Revert the changes so that PRI*8 is again defined to "*".
>> - Provide the new definitions ("hh*") when C99 printf is supported,
>> but the old ones ("*") if it's not.
>> - Do not define the PRI*8 macros when C99 printf is not supported.
>
> The third option is the correct approach according to the standard. From
> 7.8.1: "For each type that the implementation provides in <stdint.h>, the
> corresponding fprintf macros shall be defined and the corresponding fscanf
> macros shall be defined unless the implementation does not have a suitable
> fscanf length modifier for the type." If we're saying that we don't have a
> suitable modifier (i.e. we're choosing to not support hh when
> _WANT_IO_C99_FORMATS is not defined), then PRI*8 should be left undefined.
>>
>>
>>>> I do agree that it is weird that for the SCN*8 macros to be guarded with
>>>> _WANT_IO_C99_FORMATS, whilst the PRI*8 are not.
>>
>> This is likely because the old PRI*8 definitions were known to be
>> correct regardless of C99 printf support. And the reason that the
>> SCN*8 macros must be guarded is because the scanf implementation needs
>> to specifically aware of the exact type that the passed pointers point
>> to, so that the outputs can be correctly stored. There is no implicit
>> promotion to "save us" in the case of scanf.
>>
>> You might be surprised how Linux defines these macros - at least on
>> the machine I tested on, PRI*8 was "*".
>
> (This is bad for the reasons noted above.)
> Craig