This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Regression with printf 8-bit format macros


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]