From: Keith.S.Thompson+u@gmail.com   
      
   David Brown writes:   
   [...]   
   > C23 includes length specifiers with explicit bit counts, so "%w32u" is   
   > for an unsigned integer argument of 32 bits:   
   >   
   > """   
   > wN Specifies that a following b, B, d, i, o, u, x, or X conversion   
   > specifier applies to an integer argument with a specific width   
   > where N is a positive decimal integer with no leading zeros   
   > (the argument will have been promoted according to the integer   
   > promotions, but its value shall be converted to the unpromoted   
   > type); or that a following n conversion specifier applies to a   
   > pointer to an integer type argument with a width of N bits. All   
   > minimum-width integer types (7.22.1.2) and exact-width integer   
   > types (7.22.1.1) defined in the header shall be   
   > supported. Other supported values of N are implementation-defined.   
   > """   
   >   
   > That looks to me that it would be a correct specifier for uint32_t,   
      
   Yes, so for example this:   
      
    uint32_t n = 42;   
    printf("n = %w32u\n", n);   
      
   is correct, if I'm reading it correctly. It's also correct for   
   uint_least32_t, which is expected to be the same type as uint32_t   
   if the latter exists. There's also support for the [u]int_fastN_t   
   types, using for example "%wf32u" in place of "%w32u".   
      
   > and should also be fully defined behaviour for unsigned int and   
   > unsigned long if these are 32 bits wide.   
      
   No, I don't think C23 says that. If int and long happen to be the same   
   width, they are still incompatible, and there is no printf format   
   specifier that has defined behavior for both.   
      
   That first sentence is a bit ambiguous   
      
    wN Specifies that a following b, B, d, i, o, u, x, or X conversion   
    specifier applies to an integer argument with a specific width ...   
      
   but I don't think it means that it must accept *any* integer type   
   of the specified width.   
      
   Later in the same paragraph, it says that all [u]intN_t and   
   [u]int_leastN_t types shall be supported -- all such *types*, not   
   all such *widths*. And it doesn't say that the predefined types   
   shall be supported.   
      
   Paragraph 9 says:   
      
    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.   
      
   And in the description for the va_arg macro (whose second argument   
   is a type name):   
      
    If *type* is not compatible with the type of the actual   
    next argument (as promoted according to the default argument   
    promotions), the behavior is undefined, except for the following   
    cases: ...   
      
   Corresponding signed and unsigned types are supported if the value   
   is representable in both, but there's no provision for mixing int   
   and long even if they have the same width.   
      
   If printf is implemented using , what type name can it   
   pass to the va_arg() macro given a "%w32u" specification? It can   
   only pass uint32_t or uint_least32_t (or it can pass unsigned int   
   or unsigned long *if* that type is compatible with the uint32_t).   
   (And C23 adds a requirement that [u]int_leastN_t is the same type as   
   [u]intN_t if the latter exists; perhaps this is why.)   
      
   Prior to C17, there is no conversion specification that's valid for   
   both int and long, even if they're the same width. Changing that   
   in C23 would have been a significant change, but there's no mention   
   of it, even in a footnote.   
      
   The "%w..." format specifiers are simpler (and IMHO less ugly)   
   than the macros in , but they don't add any fundamental   
   new capability.   
      
   Given the format specifier "%w32u", the corresponding argument must   
   be of type uint32_t, or it can be of type int32_t and representable   
   in both, or it can be of a type compatible with [u]int32_t. I expect   
   that in most or all implementations, the undefined behavior of   
   passing an incompatible type with the same width and representation   
   will appear as if it "worked", but a compile-time warning is likely   
   if the format is a string literal.   
      
   And of course if you want to print a uint32_t value, you can always   
   cast it to unsigned long and use "%u".   
      
   --   
   Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com   
   void Void(void) { Void(); } /* The recursive call of the void */   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|