From: david.brown@hesbynett.no   
      
   On 12/01/2026 13:27, Keith Thompson wrote:   
   > 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.   
      
   That's the part that I am not at all sure about - it is, as you say,   
   ambiguous. It also refers to "a pointer to an integer type argument   
   with a width of N bits" (in the context of an "n" specifier) - that   
   sounds like "%w32n" would be happy with a "uint32_t *", "unsigned int *"   
   or "unsigned long int *" pointer (when the integer types are all 32   
   bit). It would be strange for printf to be happy with clearly   
   incompatible pointer types when the integer sizes are the same, but not   
   be happy with integer values when the sizes are the same.   
      
   But my interpretation here could well be wrong. Only the [u]intNN_t and   
   [u]int_leastNN_t types are explicitly and clearly accepted here.   
      
   >   
   > 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".   
   >   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|