Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: printf and time_t Date: Mon, 12 Jan 2026 04:27:14 -0800 Organization: None to speak of Lines: 100 Message-ID: <87qzrvow2l.fsf@example.invalid> References: <10jfol6$2u6r8$1@news.xmission.com> <10jgbp7$2vdjt$1@news.xmission.com> <10jgdu9$2t8dh$1@nntp.eternal-september.org> <10jhkso$3c9r2$3@nntp.eternal-september.org> <20260106112938.00004446@yahoo.com> <10jj9st$3jbe4$2@dont-email.me> <20260106200522.000015ea@yahoo.com> <87h5sy2rlb.fsf@example.invalid> <87qzs1gliq.fsf@example.invalid> <20260108012620.000041a9@yahoo.com> <87bjj5gei4.fsf@example.invalid> <20260108023846.0000260c@yahoo.com> <10jpi8h$15aea$1@dont-email.me> <20260109141859.00004f22@yahoo.com> <10jv3rb$15aea$2@dont-email.me> <20260111132015.000026ad@yahoo.com> <87ikd82tks.fsf@example.invalid> <20260111153201.000075f9@yahoo.com> <87ecnv3gj2.fsf@example.invalid> <10k27e7$25sqv$1@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Mon, 12 Jan 2026 12:27:19 +0000 (UTC) Injection-Info: dont-email.me; posting-host="4f47478b15b0a336821a595eb474bce0"; logging-data="2458189"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+ssuu3dNTVLj09O+V/027y" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:iY9EevzA+xr3IwvNsxZ7Yl7QK/c= sha1:MvB6Cb4GC+s16va1i8ntZLtZNpY= Xref: csiph.com comp.lang.c:396371 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 */