• printf and time_t

    From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 07:19:02 2026
    From Newsgroup: comp.lang.c

    Here's kind of an old chestnut...

    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    The answer seems to be: try stuff until the compiler doesn't warn.

    Note that there is now %z for size_t, but there really should be a "Just do
    the right thing - you're the compiler, you know what type the arg is, do
    the right thing" spec.

    It turns out that in my use case, %lu works, but how can you know?
    Note, BTW, that another way to do it is to use %d and case the time_t value
    to (int), but that seems kludgey.
    --
    Nov 4, 2008 - the day when everything went
    from being Clinton's fault to being Obama's fault.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andrey Tarasevich@noone@noone.net to comp.lang.c on Mon Jan 5 00:17:07 2026
    From Newsgroup: comp.lang.c

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended to
    be an opaque type. It has to be a real type, so it is either an integer
    of a plain floating-point type. But other than that nothing is known
    about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific way.
    Which still immediately means that you can't do it "reliably", if I
    understand what you mean correctly.
    --
    Best regards,
    Andrey


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael Sanders@porkchop@invalid.foo to comp.lang.c on Mon Jan 5 08:32:30 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 07:19:02 -0000 (UTC), Kenny McCormack wrote:

    Here's kind of an old chestnut...

    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    The answer seems to be: try stuff until the compiler doesn't warn.

    Note that there is now %z for size_t, but there really should be a "Just do the right thing - you're the compiler, you know what type the arg is, do
    the right thing" spec.

    It turns out that in my use case, %lu works, but how can you know?
    Note, BTW, that another way to do it is to use %d and case the time_t value to (int), but that seems kludgey.

    Hi Kenny not sure this will help you but check out <time.h>,
    struct tm has these members (names/meanings/types are fixed
    by the standard):

    struct tm {
    int tm_sec; // seconds after the minute [0, 60] (leap second possible)
    int tm_min; // minutes after the hour [0, 59]
    int tm_hour; // hours since midnight [0, 23]
    int tm_mday; // day of the month [1, 31]
    int tm_mon; // months since January [0, 11] (0 = Jan)
    int tm_year; // years since 1900
    int tm_wday; // days since Sunday [0, 6] (0 = Sun)
    int tm_yday; // days since January 1 [0, 365]
    int tm_isdst; // Daylight Saving Time flag
    // >0 = DST in effect
    // 0 = not in effect
    // <0 = information not available
    };

    #include <stdio.h>
    #include <time.h>

    int main(void) {
    time_t t = time(NULL);
    struct tm tm;

    localtime_r(&t, &tm);

    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
    tm.tm_year + 1900,
    tm.tm_mon + 1,
    tm.tm_mday,
    tm.tm_hour,
    tm.tm_min,
    tm.tm_sec);

    return 0;
    }
    --
    :wq
    Mike Sanders
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael Sanders@porkchop@invalid.foo to comp.lang.c on Mon Jan 5 08:46:21 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 08:32:30 -0000 (UTC), Michael Sanders wrote:

    On Mon, 5 Jan 2026 07:19:02 -0000 (UTC), Kenny McCormack wrote:

    Here's kind of an old chestnut...

    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    Well, if its just the time_t value itsself (& that is what you've
    asked for), my reply may not help so much...
    --
    :wq
    Mike Sanders
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 5 10:51:38 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 00:17:07 -0800
    Andrey Tarasevich <noone@noone.net> wrote:

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended
    to be an opaque type. It has to be a real type, so it is either an
    integer of a plain floating-point type. But other than that nothing
    is known about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific
    way. Which still immediately means that you can't do it "reliably",
    if I understand what you mean correctly.


    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 5 11:32:18 2026
    From Newsgroup: comp.lang.c

    On 05/01/2026 09:17, Andrey Tarasevich wrote:
    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended to
    be an opaque type. It has to be a real type, so it is either an integer
    of a plain floating-point type. But other than that nothing is known
    about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific way. Which still immediately means that you can't do it "reliably", if I understand what you mean correctly.


    Does being a "real type" imply that "time_t" is always an alias for a
    standard integer type or standard floating point type? If so, then a
    _Generic macro might be a solution here. If it could be an extended
    integer type (or a _BitInt type in C23 :-) ), or some other scalar type,
    then a _Generic macro will not cover all hypothetically possible cases.
    But it might still cover all practical cases of interest to the OP.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From highcrew@high.crew3868@fastmail.com to comp.lang.c on Mon Jan 5 12:48:43 2026
    From Newsgroup: comp.lang.c

    On 1/5/26 8:19 AM, Kenny McCormack wrote:
    It turns out that in my use case, %lu works, but how can you know?
    Note, BTW, that another way to do it is to use %d and case the time_t value to (int), but that seems kludgey.

    I think I'd use %jd and cast it to intmax_t

    printf("%jd\n", (intmax_t)t);

    I don't know if there's any risk in doing so.
    --
    High Crew
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Mon Jan 5 07:37:07 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 05:32, David Brown wrote:
    ...
    Does being a "real type" imply that "time_t" is always an alias for a standard integer type or standard floating point type?

    No, real types include integer types, which in turn includes the signed
    and unsigned integer types (6.2.5p22). The signed integer types include
    the extended signed integer types (6.2.5p6), and the unsigned integer
    types include the extended unsigned integer types (6.2.5p8).
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 12:45:27 2026
    From Newsgroup: comp.lang.c

    In article <20260105105138.00005f0a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    These are all good suggestions, but in the end, are all just kludgey workarounds. My two points in posting are:

    1) There really should be a generic way to print any numeric object and
    have the compiler "Do The Right Thing".

    2) Although time_t was the specific occasion for composing and posting
    this, it, of course, applies to all the other "artificial" numeric
    types. As mentioned in the OP, they seem to have come up with a
    solution for size_t; it would be nice if that were generalized.

    P.S. I like the rhythm of "long long can't go wrong"...
    --
    To be evangelical is to spend every waking moment hovering around
    two emotional states: fear and rage. Evangelicals are seriously the
    angriest and most vicious bunch of self-pitying, constantly-moaning
    whinybutts I've ever encountered.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Mon Jan 5 07:50:37 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 03:17, Andrey Tarasevich wrote:
    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended to
    be an opaque type. It has to be a real type, ...

    In C99, it was only required to be an arithmetic type. I pointed out
    that this would permit it to be, for example, double _Imaginary. I like
    to think that my comment may have been responsible for the fact that
    C2011 specified that it must be real.

    ... so it is either an integer
    of a plain floating-point type. But other than that nothing is known
    about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific way. Which still immediately means that you can't do it "reliably", if I understand what you mean correctly.

    if(1/(time_t)2)
    { // time_t is a floating point type)
    prrintf("%lg", (long double)t);
    }
    else if(0 < (time_t)-1)
    { // time_t is an unsigned integer type
    printf("%ju", (uintmax_t)t);
    }
    else // time_t is a signed integer type
    printf("%jd", (intmax_t)t);

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 5 15:21:00 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 12:45:27 -0000 (UTC)
    gazelle@shell.xmission.com (Kenny McCormack) wrote:


    P.S. I like the rhythm of "long long can't go wrong"...


    By way of free association you comment caused me to recollect short SF
    story of Fritz Leiber that was written several years before I was born.

    https://archive.org/details/Galaxy_v20n01_1961-10/page/n157/mode/2up


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From bart@bc@freeuk.com to comp.lang.c on Mon Jan 5 13:22:19 2026
    From Newsgroup: comp.lang.c

    On 05/01/2026 12:45, Kenny McCormack wrote:
    In article <20260105105138.00005f0a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    These are all good suggestions, but in the end, are all just kludgey workarounds. My two points in posting are:

    1) There really should be a generic way to print any numeric object and
    have the compiler "Do The Right Thing".

    My original C compiler had a way to do it:

    #include <stdio.h>
    #include <time.h>

    int main(void) {
    printf("%v\n", clock());
    }

    The special format "%v" (obviously only possible within a string
    literal) is translated by the compiler into a suitable default for the
    type of the corresponding expression.

    In this case (64-bit Windows), it would be "%lld". As a bonus, "%=v"
    shows the expression itself as a label; output is:

    CLOCK()=0


    2) Although time_t was the specific occasion for composing and posting
    this, it, of course, applies to all the other "artificial" numeric
    types. As mentioned in the OP, they seem to have come up with a
    solution for size_t; it would be nice if that were generalized.

    The issue is even bigger than that:

    * You need to /know/ the exact type of your expression

    * Even if you do, it might comprise mixed types and you need to figure
    out the overall type of the result

    * It may use typedefs that you have to hunt down

    * Or they may be opaque types exported from some library

    * You may need th exact type and format. But you then you change the
    types of some variables. Now all printf calls that might use those
    variables in expressions need to be checked and possibly updated.

    * Or you might just want to rearrange your print items.

    * The type might be in64_t, say, but even if you know this, the format
    will depend on whether it is implemented on top of 'long', or 'long long'.

    For some of this, a compiler like gcc /might/ report a mismatch. It can
    do that because it knows the types of the print items. But if it can do
    that, it can also insert the correct format.

    With my feature, you just do this:

    printf("%v %v %v %v", a, b, c, d);

    Who cares what the types are!



    P.S. I like the rhythm of "long long can't go wrong"...

    Unless the type is floating about with a value between 0 and 1.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 13:49:51 2026
    From Newsgroup: comp.lang.c

    In article <20260105152100.00002469@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    On Mon, 5 Jan 2026 12:45:27 -0000 (UTC)
    gazelle@shell.xmission.com (Kenny McCormack) wrote:


    P.S. I like the rhythm of "long long can't go wrong"...


    By way of free association you comment caused me to recollect short SF
    story of Fritz Leiber that was written several years before I was born.

    My free association story is that it makes me think of (and sing in my
    head) the song "Heard It In A Love Song" (Marshall Tucker Band).

    https://archive.org/details/Galaxy_v20n01_1961-10/page/n157/mode/2up

    lynx didn't find anything useful (lots of noise, but no content) at that
    URL. Care to say a bit about what it is about?
    --
    Faith doesn't give you the answers; it just stops you from asking the questions.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 13:52:20 2026
    From Newsgroup: comp.lang.c

    In article <10jgdu9$2t8dh$1@nntp.eternal-september.org>,
    bart <bc@freeuk.com> wrote:
    On 05/01/2026 12:45, Kenny McCormack wrote:
    In article <20260105105138.00005f0a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    These are all good suggestions, but in the end, are all just kludgey
    workarounds. My two points in posting are:

    1) There really should be a generic way to print any numeric object and >> have the compiler "Do The Right Thing".

    My original C compiler had a way to do it:

    #include <stdio.h>
    #include <time.h>

    int main(void) {
    printf("%v\n", clock());
    }

    The special format "%v" (obviously only possible within a string
    literal) is translated by the compiler into a suitable default for the
    type of the corresponding expression.

    Good thing. I had been about to say, in some post on this thread, that
    lots of other languages can do this (starting with, e.g., BASIC), so why
    can't C do it?

    And, although I can't quite recall at the moment which language it was, I
    know there was some language where it would do the label thing, too. I.e.,
    you would code "print foo" and it would print "foo=...".
    --
    "Unattended children will be given an espresso and a free kitten."
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 5 16:47:20 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 13:49:51 -0000 (UTC)
    gazelle@shell.xmission.com (Kenny McCormack) wrote:

    In article <20260105152100.00002469@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    On Mon, 5 Jan 2026 12:45:27 -0000 (UTC)
    gazelle@shell.xmission.com (Kenny McCormack) wrote:


    P.S. I like the rhythm of "long long can't go wrong"...


    By way of free association you comment caused me to recollect short
    SF story of Fritz Leiber that was written several years before I was
    born.

    My free association story is that it makes me think of (and sing in my
    head) the song "Heard It In A Love Song" (Marshall Tucker Band).

    https://archive.org/details/Galaxy_v20n01_1961-10/page/n157/mode/2up


    lynx didn't find anything useful (lots of noise, but no content) at
    that URL. Care to say a bit about what it is about?


    In short, beatniks on the orbit.
    For longer description, ask somebody who happens to be a native English speaker. Or for 20 minutes allow yourself to use a little less
    eccentric way of browsing web.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From richard@richard@cogsci.ed.ac.uk (Richard Tobin) to comp.lang.c on Mon Jan 5 14:53:22 2026
    From Newsgroup: comp.lang.c

    In article <10jfol6$2u6r8$1@news.xmission.com>,
    Kenny McCormack <gazelle@shell.xmission.com> wrote:
    The question is: How can you reliably printf() a time_t value?

    Do you want to print it in a human-understandable format? Or a
    non-binary format? Or just in a way that's re-readable?

    For a human-understandable format, the compiler needs to know about
    the type. Obviously this could be done for time_t, but for the
    general case there would have to be a way for libraries to provide a
    function that converts it to a string.

    To handle the non-understandable formats, there could be format
    specifiers to print binary and hex strings whose size is given by the precision, like %.*s but not treating NUL as a terminator.

    -- Richard
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 15:29:35 2026
    From Newsgroup: comp.lang.c

    In article <20260105164720.0000352f@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    By way of free association you comment caused me to recollect short
    SF story of Fritz Leiber that was written several years before I was
    born.
    ...
    lynx didn't find anything useful (lots of noise, but no content) at
    that URL. Care to say a bit about what it is about?


    In short, beatniks on the orbit.
    For longer description, ask somebody who happens to be a native English >speaker. Or for 20 minutes allow yourself to use a little less
    eccentric way of browsing web.

    Indeed. I could do that. Still, thanks for the info. I am satisfied.
    --
    So to cure the problem of arrogant incompetent rich people we should turn
    the government over to an arrogant incompetent trust fund billionaire
    who knows nothing about government and who has never held a job in his
    entire spoiled life?
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 15:36:09 2026
    From Newsgroup: comp.lang.c

    In article <10jgj92$1o88k$1@artemis.inf.ed.ac.uk>,
    Richard Tobin <richard@cogsci.ed.ac.uk> wrote:
    In article <10jfol6$2u6r8$1@news.xmission.com>,
    Kenny McCormack <gazelle@shell.xmission.com> wrote:
    The question is: How can you reliably printf() a time_t value?

    Do you want to print it in a human-understandable format? Or a
    non-binary format? Or just in a way that's re-readable?

    In the instant case, I want the "number of seconds since the Unix epoch" number. That's human-understandable enough for my purposes.

    (Note that if you really want human-readable, you can push it through
    ctime() and then you don't have to worry about the format string (it is and always will be "%s"))

    And, yes, I am assuming POSIX-ish (in fact, Linux) throughout, so don't
    really care about ISO C eccentricities.

    As I've commented in other posts on this thread, it would certainly be
    possible for a C compiler to do this - but it may not be in the spirit of C
    for it to do so. Bart has certainly shown us the way.
    --
    What are your thoughts on Alabama politicians declaring Donald Trump one
    of the greatest presidents ever?

    Alabama is ranked #47 in education out of 50 states. Now we know why.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c on Mon Jan 5 15:57:15 2026
    From Newsgroup: comp.lang.c

    gazelle@shell.xmission.com (Kenny McCormack) writes:
    Here's kind of an old chestnut...

    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html

    Use the '%s' conversion specifier.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lew Pitcher@lew.pitcher@digitalfreehold.ca to comp.lang.c on Mon Jan 5 16:23:09 2026
    From Newsgroup: comp.lang.c

    On Mon, 05 Jan 2026 10:51:38 +0200, Michael S wrote:

    On Mon, 5 Jan 2026 00:17:07 -0800
    Andrey Tarasevich <noone@noone.net> wrote:

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended
    to be an opaque type. It has to be a real type, so it is either an
    integer of a plain floating-point type. But other than that nothing
    is known about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific
    way. Which still immediately means that you can't do it "reliably",
    if I understand what you mean correctly.


    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    As Andrey pointed out, time_t can resolve to a floatingpoint type,
    so, "long long" would go wrong if the implementation typedefs it to
    float, or
    double, or
    long double.
    --
    Lew Pitcher
    "In Skills We Trust"
    Not LLM output - I'm just like this.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.lang.c on Mon Jan 5 16:34:09 2026
    From Newsgroup: comp.lang.c

    In article <10jgohd$31ebg$1@nntp.eternal-september.org>,
    Lew Pitcher <lew.pitcher@digitalfreehold.ca> wrote:
    ...
    As Andrey pointed out, time_t can resolve to a floatingpoint type,
    so, "long long" would go wrong if the implementation typedefs it to
    float, or
    double, or
    long double.

    That really doesn't matter. We're talking about POSIX here.

    Yes, I neglected to mention that in the OP (I had intended to, but it
    slipped my mind when I hit "send"), but I added it in in a subsequent
    post. So, the qualifier is there.
    --
    "We are in the beginning of a mass extinction, and all you can talk
    about is money and fairy tales of eternal economic growth."

    - Greta Thunberg -
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 5 17:34:14 2026
    From Newsgroup: comp.lang.c

    On 05/01/2026 17:23, Lew Pitcher wrote:
    On Mon, 05 Jan 2026 10:51:38 +0200, Michael S wrote:

    On Mon, 5 Jan 2026 00:17:07 -0800
    Andrey Tarasevich <noone@noone.net> wrote:

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended
    to be an opaque type. It has to be a real type, so it is either an
    integer of a plain floating-point type. But other than that nothing
    is known about it. There's really no point in printing it.

    If you still want to, you can do it in some implementation-specific
    way. Which still immediately means that you can't do it "reliably",
    if I understand what you mean correctly.


    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    As Andrey pointed out, time_t can resolve to a floatingpoint type,
    so, "long long" would go wrong if the implementation typedefs it to
    float, or
    double, or
    long double.


    As I understand it, time_t is intended to be suitable for holding a
    number of seconds (it is used for that purpose in struct timespec). So
    while it might be a floating point type, it is unlikely to be holding a
    value greater than 2 ** 63 (21 times the age of the universe in
    seconds). But I think there is still a hypothetical possibility that
    the time_t value returned by, say, the "time" function, could have a
    different scaling. If that were scaled in nanoseconds, you could
    overflow long long after only about 292 years.

    Perhaps you are safer converting to _BitInt(128) :-)

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 5 19:23:51 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC)
    Lew Pitcher <lew.pitcher@digitalfreehold.ca> wrote:

    On Mon, 05 Jan 2026 10:51:38 +0200, Michael S wrote:

    On Mon, 5 Jan 2026 00:17:07 -0800
    Andrey Tarasevich <noone@noone.net> wrote:

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:
    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is
    intended to be an opaque type. It has to be a real type, so it is
    either an integer of a plain floating-point type. But other than
    that nothing is known about it. There's really no point in
    printing it.

    If you still want to, you can do it in some implementation-specific
    way. Which still immediately means that you can't do it "reliably",
    if I understand what you mean correctly.


    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    As Andrey pointed out, time_t can resolve to a floatingpoint type,
    so, "long long" would go wrong if the implementation typedefs it to
    float, or
    double, or
    long double.


    Reading literally what you wrote makes no sense, so I assume that you
    meant that 'it' above constitutes time_t rather than 'long long'.

    The rest of the post assumes 64-bit 'long long'.
    'typedef float time_t' where float==IEEE binary32 is a bad idea, because
    you lose your 1sec resolution after 7 months. I.e. with Unix epoch you
    lost it a year or two before Ritchi finished his first C compiler.
    'typedef double time_t' means that you lost 1 sec resolution ~3
    orders of magnitude before you got a chance to overflow 'long long'.

    Only in case of 'typedef long double time_t' there is a chance that
    overflow happens before resolution is lost. But barely so for 80-bit
    long double format prevalent on i386/AMD64 computers.



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Mon Jan 5 13:11:22 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Mon Jan 5 13:14:12 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 03:51, Michael S wrote:
    ....
    I can't think about situation in which casting time_t value to 'long
    long' can go wrong.

    If time_t is a floating point type, or even an extended integer type
    with a greater range than long long, or even simply unsigned long long,
    the value could be too large to store in long long, in which case the conversion has undefined behavior. If time_t is a flaoting point type,
    another problem is that the conversion will discard the fractional part
    of the value. Depending upon how time_t is scaled, that might result is
    a large error.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 5 19:28:59 2026
    From Newsgroup: comp.lang.c

    On 05/01/2026 19:11, James Kuyper wrote:
    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.

    7.27.1p4:

    The range and precision of times representable in clock_t and time_t are implementation-defined. The timespec structure shall contain at least
    the following members, in any order. The semantics of the members and
    their normal ranges are expressed in the comments.

    time_t tv_sec; // whole seconds -- >= 0
    long tv_nsec; // nanoseconds -- [0, 999999999]


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Mon Jan 5 14:00:07 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 13:28, David Brown wrote:
    On 05/01/2026 19:11, James Kuyper wrote:
    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.

    7.27.1p4:

    The range and precision of times representable in clock_t and time_t are implementation-defined. The timespec structure shall contain at least
    the following members, in any order. The semantics of the members and
    their normal ranges are expressed in the comments.

    time_t tv_sec; // whole seconds -- >= 0
    long tv_nsec; // nanoseconds -- [0, 999999999]

    I'm not sure how I missed that in my search. In the latest draft of the standard I could find, n3685.pdf, that's in 7.21.1p6. I found struct
    timespec mentioned in 7.21.1p5 with no detailed specification, and
    didn't bother reading the next paragraph, which provides that
    specification. If I had thought about it, I would have realized that the
    same was true of struct tm, which I know from long experience has a
    detailed specification.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 5 20:38:14 2026
    From Newsgroup: comp.lang.c

    On 05/01/2026 20:00, James Kuyper wrote:
    On 2026-01-05 13:28, David Brown wrote:
    On 05/01/2026 19:11, James Kuyper wrote:
    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.

    7.27.1p4:

    The range and precision of times representable in clock_t and time_t are
    implementation-defined. The timespec structure shall contain at least
    the following members, in any order. The semantics of the members and
    their normal ranges are expressed in the comments.

    time_t tv_sec; // whole seconds -- >= 0
    long tv_nsec; // nanoseconds -- [0, 999999999]

    I'm not sure how I missed that in my search.

    Probably in the same way I regularly miss details...

    In the latest draft of the
    standard I could find, n3685.pdf, that's in 7.21.1p6. I found struct
    timespec mentioned in 7.21.1p5 with no detailed specification, and
    didn't bother reading the next paragraph, which provides that
    specification. If I had thought about it, I would have realized that the
    same was true of struct tm, which I know from long experience has a
    detailed specification.

    There is still nothing, as far as I can see, that guarantees other
    functions returning time_t work in seconds.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Jan 5 14:41:26 2026
    From Newsgroup: comp.lang.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.

    Yes, but also no.

    struct timespec contains at least the following members, in any order:

    time_t tv_sec; // whole seconds rCo reN 0
    long tv_nsec; // nanoseconds rCo [0, 999999999]

    But a footnote says:

    The tv_sec member is a linear count of seconds and may not have
    the normal semantics of a time_t.

    This makes for a simpler implementation *if* the time_t value
    returned by time(), and operated on by difftime(), mktime(), ctime(),
    gmtime(), and localtime(), happens to hold a linear count of seconds
    (as it does on most systems).

    It's odd that time_t is used for two potentially very different
    purposes, one as a member of struct timespec and another as used
    in all other contexts. And I would guess that a lot of code that
    uses struct timespec *assumes* that its time_t member has the same
    semantics value returned by time(NULL).

    For example, as I write this the time is 2026-01-05 22:32:57.881 UTC.
    The corresponding value returned by time() is 1767652377 (seconds
    since the 1970 epoch, no milliseconds). An implementation could
    represent the current time (the value returned by time(NULL) as a
    64-bit integer with the value 20260105223257881. But timespec_get()
    would still have to set the tv_sec member to 1767652377.

    It might have been cleaner either to require that time_t represents a
    count of seconds, or to use a type other than time_t for the tv_sec
    member of struct timespec.

    I know there are systems that use something other than seconds
    since 1970 in the underlying time representation, but are there any
    C implementations that don't use seconds since 1970? (POSIX and
    Windows both specify that.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Jan 5 15:04:22 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC)
    Lew Pitcher <lew.pitcher@digitalfreehold.ca> wrote:
    [...]
    As Andrey pointed out, time_t can resolve to a floatingpoint type,
    so, "long long" would go wrong if the implementation typedefs it to
    float, or
    double, or
    long double.

    Reading literally what you wrote makes no sense, so I assume that you
    meant that 'it' above constitutes time_t rather than 'long long'.

    The rest of the post assumes 64-bit 'long long'.
    'typedef float time_t' where float==IEEE binary32 is a bad idea, because
    you lose your 1sec resolution after 7 months. I.e. with Unix epoch you
    lost it a year or two before Ritchi finished his first C compiler.
    'typedef double time_t' means that you lost 1 sec resolution ~3
    orders of magnitude before you got a chance to overflow 'long long'.

    Only in case of 'typedef long double time_t' there is a chance that
    overflow happens before resolution is lost. But barely so for 80-bit
    long double format prevalent on i386/AMD64 computers.

    Assuming IEEE floating-point, and assuming time_t represents seconds
    since the usual 1970 epoch, the current resolution of a 64-bit
    floating-point time_t would be about 238 nanoseconds. It has
    that same resolution for any time from 2004-01-10 to 2038-01-18.
    (The resolution doubles when the number of seconds since 1970
    exceeds a power of 2.) The resolution doesn't reach one second
    until 142715360-12-05 (that's a Friday if we're still using the
    same calendar).

    I don't suggest that using type double for time_t would be a good
    idea, and in fact POSIX requires time_t to be an integer type.
    (I think Windows does as well, but the documentation is less clear,
    or perhaps I'm missing something.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Tue Jan 6 01:23:47 2026
    From Newsgroup: comp.lang.c

    On Mon, 05 Jan 2026 15:04:22 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    (I think Windows does as well, but the documentation is less clear,
    or perhaps I'm missing something.)


    On Windows time_t belongs to implementation of C language
    rather than to OS API/ABI. So, Windows OS can't have any
    requirements for time_t beyond requirement of C Standard.

    If we are talking specifically about Microsoft's implementation then
    it is easy to observe that time_t is 64-bit integer by default and
    32-bit integer when user defines macro _USE_32BIT_TIME_T

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.c on Tue Jan 6 00:22:29 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type <https://manpages.debian.org/time_t(3type)>.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.c on Tue Jan 6 00:27:04 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 13:22:19 +0000, bart wrote:

    In this case (64-bit Windows), it would be "%lld".

    Section 7.8 of the C spec defines macros you can use so you donrCOt have
    to hard-code assumptions about the lengths of integers in
    printf-format strings.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.c on Tue Jan 6 00:30:53 2026
    From Newsgroup: comp.lang.c

    On Mon, 5 Jan 2026 07:37:07 -0500, James Kuyper wrote:

    On 2026-01-05 05:32, David Brown wrote:
    ...
    Does being a "real type" imply that "time_t" is always an alias for
    a standard integer type or standard floating point type?

    No, real types include integer types, which in turn includes the
    signed and unsigned integer types (6.2.5p22). The signed integer
    types include the extended signed integer types (6.2.5p6), and the
    unsigned integer types include the extended unsigned integer types
    (6.2.5p8).

    They could have said rCLnumeric typesrCY to avoid confusion with the mathematical usage ...
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Jan 5 20:00:50 2026
    From Newsgroup: comp.lang.c

    Lawrence DrCOOliveiro <ldo@nz.invalid> writes:
    On Mon, 5 Jan 2026 07:37:07 -0500, James Kuyper wrote:
    On 2026-01-05 05:32, David Brown wrote:
    ...
    Does being a "real type" imply that "time_t" is always an alias for
    a standard integer type or standard floating point type?

    No, real types include integer types, which in turn includes the
    signed and unsigned integer types (6.2.5p22). The signed integer
    types include the extended signed integer types (6.2.5p6), and the
    unsigned integer types include the extended unsigned integer types
    (6.2.5p8).

    They could have said rCLnumeric typesrCY to avoid confusion with the mathematical usage ...

    No, complex types are numeric types (or arithmetic types in C terms).

    And in mathematical terms, both integer types and real floating types
    represent subsets of the mathematical real numbers (plus nans and
    infinities for the real floating types).
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Tue Jan 6 11:29:38 2026
    From Newsgroup: comp.lang.c

    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    On Mon, 5 Jan 2026 13:22:19 +0000, bart wrote:

    In this case (64-bit Windows), it would be "%lld".

    Section 7.8 of the C spec defines macros you can use so you donrCOt have
    to hard-code assumptions about the lengths of integers in
    printf-format strings.
    Did you ever try to use them? They look ugly.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Tue Jan 6 14:51:52 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 23:41, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 2026-01-05 11:34, David Brown wrote:
    ...
    As I understand it, time_t is intended to be suitable for holding a
    number of seconds ...

    The standard says nothing about that.

    ... (it is used for that purpose in struct timespec). ...

    The standard says nothing to connect time_t to struct timespec.

    Yes, but also no.

    struct timespec contains at least the following members, in any order:

    time_t tv_sec; // whole seconds rCo reN 0
    long tv_nsec; // nanoseconds rCo [0, 999999999]

    But a footnote says:

    The tv_sec member is a linear count of seconds and may not have
    the normal semantics of a time_t.

    This makes for a simpler implementation *if* the time_t value
    returned by time(), and operated on by difftime(), mktime(), ctime(), gmtime(), and localtime(), happens to hold a linear count of seconds
    (as it does on most systems).

    Hmm.. - my post is not aiming in your direction but this statement
    made me curious. - A linear count (in the sense of TAI) should then
    show a difference between civil time and [TAI-]seconds since Epoch.

    A quick test shows that there's no leap seconds considered. So no
    "linear count" (in the sense of TAI). Leap seconds are disregarded
    in the "linear" seconds count.


    It's odd that time_t is used for two potentially very different
    purposes, one as a member of struct timespec and another as used
    in all other contexts.

    Semantically it might have made sense if its used for differentiating
    internal TAI (time_t) from UTC or local time on the UI (struct tm).

    Janis

    And I would guess that a lot of code that
    uses struct timespec *assumes* that its time_t member has the same
    semantics value returned by time(NULL).

    For example, as I write this the time is 2026-01-05 22:32:57.881 UTC.
    The corresponding value returned by time() is 1767652377 (seconds
    since the 1970 epoch, no milliseconds). An implementation could
    represent the current time (the value returned by time(NULL) as a
    64-bit integer with the value 20260105223257881. But timespec_get()
    would still have to set the tv_sec member to 1767652377.

    It might have been cleaner either to require that time_t represents a
    count of seconds, or to use a type other than time_t for the tv_sec
    member of struct timespec.

    I know there are systems that use something other than seconds
    since 1970 in the underlying time representation, but are there any
    C implementations that don't use seconds since 1970? (POSIX and
    Windows both specify that.)


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Tue Jan 6 10:22:28 2026
    From Newsgroup: comp.lang.c

    On 2026-01-05 19:22, Lawrence DrCOOliveiro wrote:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type <https://manpages.debian.org/time_t(3type)>.

    Which means that implementations where time_t has a floating point type
    cannot comply with POSIX; many implementations fail to do so.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Tue Jan 6 10:31:41 2026
    From Newsgroup: comp.lang.c

    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you donrCOt have
    to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    If you know that an expression has one of the standard-named types or
    typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression has
    one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it. If you have a
    value that is not known to be of one of those types, but is known to be convertible to one of those types without change of value, you should
    convert it to one of those types.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lew Pitcher@lew.pitcher@digitalfreehold.ca to comp.lang.c on Tue Jan 6 15:45:37 2026
    From Newsgroup: comp.lang.c

    On Tue, 06 Jan 2026 10:22:28 -0500, James Kuyper wrote:

    On 2026-01-05 19:22, Lawrence DrCOOliveiro wrote:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type

    Actually, POSIX does not say that.

    <https://manpages.debian.org/time_t(3type)>.

    The Debian manpages do not necessarily represent current POSIX standards.

    The current online POSIX standards pages say that, among others, time_t
    "shall be defined as arithmetic types of an appropriate length" (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html)

    The current POSIX definition of time(2) does mention integer values, but
    only as historic reference, and refers to the definition of time_t in
    <time.h> (https://pubs.opengroup.org/onlinepubs/9799919799/functions/time.html)

    The current POSIX definition <time.h> says that the <time.h> header
    "shall define the clock_t, size_t, time_t, types as described in <sys/types.h>."
    (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html)

    And, the current POSIX definition of the <sys/types.h> header says, as above, that time_t shall be defined as an arithmetic type.

    Which means that implementations where time_t has a floating point type cannot comply with POSIX; many implementations fail to do so.

    In practice, the POSIX specs likely means that time_t will represent an
    integer of some size, but the POSIX specs do /not/ say that time_t /must/
    be an integer.
    --
    Lew Pitcher
    "In Skills We Trust"
    Not LLM output - I'm just like this.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael =?ISO-8859-1?Q?B=E4uerle?=@michael.baeuerle@gmx.net to comp.lang.c on Tue Jan 6 17:00:43 2026
    From Newsgroup: comp.lang.c

    Lew Pitcher wrote:
    On Tue, 06 Jan 2026 10:22:28 -0500, James Kuyper wrote:
    On 2026-01-05 19:22, Lawrence DrCOOliveiro wrote:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type

    Actually, POSIX does not say that.

    <https://manpages.debian.org/time_t(3type)>.

    The Debian manpages do not necessarily represent current POSIX standards.

    The current online POSIX standards pages say that, among others, time_t "shall be defined as arithmetic types of an appropriate length" (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html)

    Looks like you looked at an old version. Currently there is:
    |
    | [CX] time_t shall be an integer type with a width (see <stdint.h>) of at least 64 bits.
    | [...]
    | Austin Group Defect 1462 is applied, changing time_t to have a width of at least 64 bits.

    It refers to this issue:
    <https://www.austingroupbugs.net/view.php?id=1462>
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lew Pitcher@lew.pitcher@digitalfreehold.ca to comp.lang.c on Tue Jan 6 16:08:44 2026
    From Newsgroup: comp.lang.c

    On Tue, 06 Jan 2026 17:00:43 +0100, Michael B|nuerle wrote:

    Lew Pitcher wrote:
    On Tue, 06 Jan 2026 10:22:28 -0500, James Kuyper wrote:
    On 2026-01-05 19:22, Lawrence DrCOOliveiro wrote:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type

    Actually, POSIX does not say that.

    <https://manpages.debian.org/time_t(3type)>.

    The Debian manpages do not necessarily represent current POSIX standards.

    The current online POSIX standards pages say that, among others, time_t
    "shall be defined as arithmetic types of an appropriate length"
    (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html)

    Looks like you looked at an old version. Currently there is:
    |
    | [CX] time_t shall be an integer type with a width (see <stdint.h>) of at least 64 bits.
    | [...]
    | Austin Group Defect 1462 is applied, changing time_t to have a width of at least 64 bits.

    Do you have a URL reference for this? I got my POSIX references direct from the Open Group's
    "current standards" links. The time(2), <time.h> and <sys/types.h> webpages are all
    headed:
    The Open Group Base Specifications Issue 8
    IEEE Std 1003.1-2024

    Perhaps they have not yet applied the defect remediation to the online reference.

    It refers to this issue:
    <https://www.austingroupbugs.net/view.php?id=1462>
    --
    Lew Pitcher
    "In Skills We Trust"
    Not LLM output - I'm just like this.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lew Pitcher@lew.pitcher@digitalfreehold.ca to comp.lang.c on Tue Jan 6 16:18:39 2026
    From Newsgroup: comp.lang.c

    On Tue, 06 Jan 2026 17:00:43 +0100, Michael B|nuerle wrote:

    Lew Pitcher wrote:
    On Tue, 06 Jan 2026 10:22:28 -0500, James Kuyper wrote:
    On 2026-01-05 19:22, Lawrence DrCOOliveiro wrote:
    On Mon, 5 Jan 2026 16:23:09 -0000 (UTC), Lew Pitcher wrote:

    As Andrey pointed out, time_t can resolve to a floatingpoint type,

    POSIX says time_t is an integer type

    Actually, POSIX does not say that.

    <https://manpages.debian.org/time_t(3type)>.

    The Debian manpages do not necessarily represent current POSIX standards.

    The current online POSIX standards pages say that, among others, time_t
    "shall be defined as arithmetic types of an appropriate length"
    (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html)

    Looks like you looked at an old version. Currently there is:
    |
    | [CX] time_t shall be an integer type with a width (see <stdint.h>) of at least 64 bits.
    | [...]
    | Austin Group Defect 1462 is applied, changing time_t to have a width of at least 64 bits.

    It refers to this issue:
    <https://www.austingroupbugs.net/view.php?id=1462>

    Ok, I've looked at the bugreport, and it looks like they /have/ updated the online documentation, as per the bug resolution. I missed the crucial part
    in <sys/types.h> that you quoted.

    Sorry. I'll be quiet now.
    --
    Lew Pitcher
    "In Skills We Trust"
    Not LLM output - I'm just like this.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Tue Jan 6 11:19:14 2026
    From Newsgroup: comp.lang.c

    On 2026-01-06 11:08, Lew Pitcher wrote:
    On Tue, 06 Jan 2026 17:00:43 +0100, Michael B|nuerle wrote:

    Lew Pitcher wrote:
    ...
    The current online POSIX standards pages say that, among others, time_t
    "shall be defined as arithmetic types of an appropriate length"
    (https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html)

    I followed the link Lew provided, and found precisely the text quoted by Michael:

    Looks like you looked at an old version. Currently there is:
    |
    | [CX] time_t shall be an integer type with a width (see <stdint.h>) of at least 64 bits.
    | [...]
    | Austin Group Defect 1462 is applied, changing time_t to have a width of at least 64 bits.

    The part where it says that time_t shall be an integer type is in a
    separate section titled "Additionally", 27 lines of text after it says
    "shall be defined as arithmetic types ...".

    Do you have a URL reference for this? I got my POSIX references direct from the Open Group's
    "current standards" links. The time(2), <time.h> and <sys/types.h> webpages are all
    headed:
    The Open Group Base Specifications Issue 8
    IEEE Std 1003.1-2024

    Perhaps they have not yet applied the defect remediation to the online reference.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Tue Jan 6 20:05:22 2026
    From Newsgroup: comp.lang.c

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you donrCOt
    have to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.
    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.
    If you know that an expression has one of the standard-named types or typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression
    has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.
    I should? Really?
    Sorry, James, but you have no authority to make such statements.
    Unless you meant colloquial 'you' rather than a person participating on
    Usenet under nick Michael_S.
    If you have
    a value that is not known to be of one of those types, but is known
    to be convertible to one of those types without change of value, you
    should convert it to one of those types.
    That is better advice.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c on Tue Jan 6 18:16:51 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:


    If you know that an expression has one of the standard-named types or
    typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression
    has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Tue Jan 6 16:29:04 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you donrCOt
    have to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    If unsigned int and unsigned long happen to be the same size, both
    are likely to print "42". But what if your code is later compiled
    on a system with 32-bit unsigned int and 64-bit unsigned long?

    Even if I were certain the code would never be ported (and such
    certainty is often unjustified), I'd much rather use the correct
    code than waste time figuring out which incorrect code will happen
    to "work" on the current system, with the current version of the
    compiler and runtime library. Oh, and gcc and clang both warn
    about an incorrect format string.

    I agree that the macros in <stdint.h> are ugly, and I rarely
    use them. If I want to print an integer value whose type I don't
    know, I'll probably cast to a predefined type that I know to be
    wide enough and use the specifier for that type. Though now that
    I think about it, I'm more likely to do that in throwaway code;
    for production code, I'd be more likely to use the <stdint.h> macros.

    [...]
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.lang.c on Tue Jan 6 19:44:47 2026
    From Newsgroup: comp.lang.c

    On 2026-01-06 13:05, Michael S wrote:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you donrCOt
    have to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?


    It depends.

    When I know for sure that incorrectness has no consequences, like

    If it did in fact have no consequences, it wouldn't be incorrect. It's
    the bad consequences of using the wrong format specifier that are the
    reason you should be avoiding doing so. It has undefined behavior, but
    the most common consequence is relatively mild - it just prints out the
    wrong value. Only in unusual circumstance can it result in memory access problems, or other more serious consequences.

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or even
    48 bits. It is NOT the right specifier to use for any of the standard typedefs, such as time_t or uint32_t, unless you are certain that it is
    a typedef for unsigned long by the particular implementation you're
    currently using. The reason that they are typedefs is precisely because
    they can be typedef'd to different types by different implementations.

    If you know that an expression has one of the standard-named types or
    typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression
    has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    It is not a command, it is advice. You're free to ignore it. If you make
    a habit of ignoring it, you're likely to someday find that your code malfunctions when porting to a new platform.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Tue Jan 6 17:14:20 2026
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    [...]
    I agree that the macros in <stdint.h> are ugly, and I rarely
    use them. If I want to print an integer value whose type I don't
    know, I'll probably cast to a predefined type that I know to be
    wide enough and use the specifier for that type. Though now that
    I think about it, I'm more likely to do that in throwaway code;
    for production code, I'd be more likely to use the <stdint.h> macros.

    Correction: the macros are defined in <inttypes.h>, not <stdint.h>. (<inttypes.h> includes <stdint.h> and extends it.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From bart@bc@freeuk.com to comp.lang.c on Wed Jan 7 01:14:21 2026
    From Newsgroup: comp.lang.c

    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or even
    48 bits.

    So not "%lu"?


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Wed Jan 7 13:41:54 2026
    From Newsgroup: comp.lang.c

    On Wed, 7 Jan 2026 01:14:21 +0000
    bart <bc@freeuk.com> wrote:

    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or
    even 48 bits.

    So not "%lu"?



    gcc and clang maintainers certainly think so.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Wed Jan 7 14:01:34 2026
    From Newsgroup: comp.lang.c

    On Tue, 06 Jan 2026 16:29:04 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    donrCOt have to hard-code assumptions about the lengths of
    integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    No, I don't think that it is much uglier. At worst, I think that
    correct version is tiny bit uglier. Not enough for beauty to win over "correctness", even when correctness is non-consequential.
    I hoped that you followed the sub-thread from the beginning and did not
    lost the context yet. Which is (everywhere except LIN64)
    uint32_t n = 42;
    printf("n = %u\n", n); // incorrect
    printf("n = " PRIu32 "\n", n); // correct
    or on LIN64
    uint64_t n = 42;
    printf("n = %llu\n", n); // incorrect
    printf("n = " PRIu64 "\n", n); // correct
    Here in my book beauty wins by landslide.
    Although really it is not beauty wins. It's ugliness loses.
    If unsigned int and unsigned long happen to be the same size, both
    are likely to print "42". But what if your code is later compiled
    on a system with 32-bit unsigned int and 64-bit unsigned long?

    Even if I were certain the code would never be ported (and such
    certainty is often unjustified), I'd much rather use the correct
    code than waste time figuring out which incorrect code will happen
    to "work" on the current system, with the current version of the
    compiler and runtime library. Oh, and gcc and clang both warn
    about an incorrect format string.

    I agree that the macros in <stdint.h> are ugly, and I rarely
    use them. If I want to print an integer value whose type I don't
    know, I'll probably cast to a predefined type that I know to be
    wide enough and use the specifier for that type. Though now that
    I think about it, I'm more likely to do that in throwaway code;
    for production code, I'd be more likely to use the <stdint.h> macros.

    [...]

    I am happy that in practice your position is not too different from my position. It's just that irresistible urge of you to defend "right"
    things in NG discussions that creates an appearance of disagreeing.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Jan 7 04:28:05 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 06 Jan 2026 16:29:04 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    donrCOt have to hard-code assumptions about the lengths of
    integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    No, I don't think that it is much uglier. At worst, I think that
    correct version is tiny bit uglier. Not enough for beauty to win over "correctness", even when correctness is non-consequential.

    I hoped that you followed the sub-thread from the beginning and did not
    lost the context yet.

    The context to which I replied was you favoring beauty over
    correctness and using "%u" to print an unsigned long value as
    an example.

    I find it difficult to express how strongly I disagree.

    Which is (everywhere except LIN64)
    uint32_t n = 42;
    printf("n = %u\n", n); // incorrect
    printf("n = " PRIu32 "\n", n); // correct

    printf("n = %lu\n", (unsigned long)n); // also correct

    or on LIN64
    uint64_t n = 42;
    printf("n = %llu\n", n); // incorrect
    printf("n = " PRIu64 "\n", n); // correct

    printf("n = %llu\n", (unsigned long long)n); // also correct

    As far as I'm concerned, the incorrect versions aren't even worth
    considering.

    Here in my book beauty wins by landslide.
    Although really it is not beauty wins. It's ugliness loses.

    I don't think much of your book.

    [...]

    I am happy that in practice your position is not too different from my position. It's just that irresistible urge of you to defend "right"
    things in NG discussions that creates an appearance of disagreeing.

    I don't know how you reached the conclusion that our positions are
    "not too different". As far as I can tell, they are completely
    different. You would knowingly write incorrect code.

    Given two alternative pieces of code, I prefer the prettier one
    if both are correct (and that is of course a matter of taste).
    But if one is incorrect, it doesn't matter how pretty it is.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Wed Jan 7 05:02:39 2026
    From Newsgroup: comp.lang.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-05 03:17, Andrey Tarasevich wrote:

    On Sun 1/4/2026 11:19 PM, Kenny McCormack wrote:

    The question is: How can you reliably printf() a time_t value?
    What conversion spec should you use?

    You can't. As far as the language is concerned, `time_t` is intended
    to be an opaque type. It has to be a real type, ...

    In C99, it was only required to be an arithmetic type. I pointed out
    that this would permit it to be, for example, double _Imaginary. [...]

    It's hard to imagine how time_t being an imaginary type could
    provide the semantics described in the C standard for time_t.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Wed Jan 7 05:06:28 2026
    From Newsgroup: comp.lang.c

    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named types or
    typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression
    has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    Really? What passage in the C standard is being paraphrased?
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c on Wed Jan 7 15:45:10 2026
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence DrCOOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you donrCOt
    have to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From bart@bc@freeuk.com to comp.lang.c on Wed Jan 7 15:54:06 2026
    From Newsgroup: comp.lang.c

    On 07/01/2026 11:41, Michael S wrote:
    On Wed, 7 Jan 2026 01:14:21 +0000
    bart <bc@freeuk.com> wrote:

    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or
    even 48 bits.

    So not "%lu"?



    gcc and clang maintainers certainly think so.


    They think it is correct or not correct? If I compile this:

    #include <stdio.h>

    int main() {
    unsigned long a=0;
    printf("%u", a);
    }

    then gcc complains (given suitable options):

    warning: format '%u' expects argument of type 'unsigned int', but
    argument 2 has type 'long unsigned int' [-Wformat=]

    The suggests it is not correct.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Wed Jan 7 18:17:16 2026
    From Newsgroup: comp.lang.c

    On Wed, 7 Jan 2026 15:54:06 +0000
    bart <bc@freeuk.com> wrote:

    On 07/01/2026 11:41, Michael S wrote:
    On Wed, 7 Jan 2026 01:14:21 +0000
    bart <bc@freeuk.com> wrote:

    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with
    32-bit longs, or like using %llu to print 'unsigned long' on
    target with 64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36,
    or even 48 bits.

    So not "%lu"?



    gcc and clang maintainers certainly think so.


    They think it is correct or not correct? If I compile this:

    #include <stdio.h>

    int main() {
    unsigned long a=0;
    printf("%u", a);
    }

    then gcc complains (given suitable options):

    warning: format '%u' expects argument of type 'unsigned int', but
    argument 2 has type 'long unsigned int' [-Wformat=]

    The suggests it is not correct.

    May be, I was not sufficiently clear, but my post was agreeing with
    your point.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Wed Jan 7 12:45:30 2026
    From Newsgroup: comp.lang.c

    On 2026-01-06 20:14, bart wrote:
    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on-a target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or even
    48 bits.

    So not "%lu"?

    I was so wrapped up in making my point about the differences between
    standard named types and the <stdint.h> typedefs that I failed to notice
    he was using the wrong specifier for unsigned long. You're right, it
    should be "%lu".

    On a different point, I used time_t as an example. It would have been
    better to use ptrdiff_t instead, since <inttypes.h> has a macro for that
    type, and doesn't have one for time_t.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Wed Jan 7 12:58:38 2026
    From Newsgroup: comp.lang.c

    On 2026-01-07 08:02, Tim Rentsch wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-05 03:17, Andrey Tarasevich wrote:
    ...
    You can't. As far as the language is concerned, `time_t` is intended
    to be an opaque type. It has to be a real type, ...

    In C99, it was only required to be an arithmetic type. I pointed out
    that this would permit it to be, for example, double _Imaginary. [...]

    It's hard to imagine how time_t being an imaginary type could
    provide the semantics described in the C standard for time_t.

    You'll need to elaborate on that. time_t is an opaque type which could,
    on one implementation, have been long double. Another implementation
    could have stored the same value as the imaginary component of
    _Imaginary long double, and could work with that value the same way as
    the first one. It would be a perverse implementation, but I see no
    serious obstacles to creating such an implementation. A good optimizer
    might even generate exactly the same machine code from C source code for
    the two implementations.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Wed Jan 7 13:08:33 2026
    From Newsgroup: comp.lang.c

    On 2026-01-07 08:06, Tim Rentsch wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named types or
    typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression
    has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    Really? What passage in the C standard is being paraphrased?

    This is advice, not paraphrased text from the C standard. It's based
    upon several facts that are mentioned in the text of the standard:

    1. <stdint.h> has typedefs for a variety integer types. They are
    typedefs precisely because they can, in general, specify different types
    on different implementations of C.

    2. <inttypes.h> contains macros for printf and scanf type specifiers appropriate for use with those typedefs.

    3. Using an inappropriate type specifier in either the printf() or
    scanf() families has undefined behavior, something that I generally want
    to avoid.

    For me, throughout most of my career, a high degree of portability was
    always required of my delivered code. Therefore, the desirability of
    using the <inttypes.h> type specifier macros, despite their clumsiness, follows from those facts. For other people, who don't mind restricting
    the portability of their code to platforms where it doesn't make a
    difference, the simplicity of using a fixed type specifier is more
    important.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.c on Wed Jan 7 20:31:37 2026
    From Newsgroup: comp.lang.c

    On Wed, 7 Jan 2026 12:45:30 -0500, James Russell Kuyper Jr. wrote:

    On a different point, I used time_t as an example. It would have
    been better to use ptrdiff_t instead, since <inttypes.h> has a macro
    for that type, and doesn't have one for time_t.

    This is why you have configure scripts, so they can figure out the
    right types to use for building on your platform.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Jan 7 13:28:45 2026
    From Newsgroup: comp.lang.c

    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence D|ore4raoOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you don|ore4raot
    have to hard-code assumptions about the lengths of integers in
    printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.

    In the quoted paragraph above, Michael wrote about using %u to print
    unsigned long, not about using %u to print some type hidden behind
    a typedef. If he didn't mean that, he can say so.

    But even if he meant to talk about printing, say, uint64_t values,
    my point stands.

    I wouldn't define my own "uint64" type. I'd just use "uint64_t",
    defined in <stdint.h>. And I'd use one of several *correct* ways
    to print uint64_t values.

    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same width on
    the current implementation), do you really prefer the version marked as "incorrect"?
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Jan 7 13:32:27 2026
    From Newsgroup: comp.lang.c

    Lawrence DrCOOliveiro <ldo@nz.invalid> writes:
    On Wed, 7 Jan 2026 12:45:30 -0500, James Russell Kuyper Jr. wrote:
    On a different point, I used time_t as an example. It would have
    been better to use ptrdiff_t instead, since <inttypes.h> has a macro
    for that type, and doesn't have one for time_t.

    This is why you have configure scripts, so they can figure out the
    right types to use for building on your platform.

    I don't follow. ptrdiff_t is defined in <stddef.h>, and is the correct
    type for the result of subtracting two pointers. What relevant
    information would a configure script give you?
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Thu Jan 8 01:26:20 2026
    From Newsgroup: comp.lang.c

    On Wed, 07 Jan 2026 13:28:45 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence D|ore4raoOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    don|ore4raot have to hard-code assumptions about the lengths of
    integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.

    In the quoted paragraph above, Michael wrote about using %u to print
    unsigned long, not about using %u to print some type hidden behind
    a typedef. If he didn't mean that, he can say so.

    But even if he meant to talk about printing, say, uint64_t values,
    my point stands.

    I wouldn't define my own "uint64" type. I'd just use "uint64_t",
    defined in <stdint.h>. And I'd use one of several *correct* ways
    to print uint64_t values.

    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same width
    on the current implementation), do you really prefer the version
    marked as "incorrect"?

    I hoped that I already clarified that point more than one time.
    Obviously, I hoped wrong.
    In the case I am talking about n declared as uint32_t.
    uint32_t is an alias of 'unsigned long' on 32-bit embedded targets, on
    32-bit Linux, on 32-bit Windows and on 64-bit Windows. It is
    alias of 'unsigned int' on 64-bit Linux.
    Sometimes I move code between targets by myself, sometimes, rarely,
    other people do it. I don't want to have different versions of the code
    and I don't want to use ugly standard specifiers. Between two pretty
    and working variants I prefer the shorter one. Partly because it is
    guaranteed to work correctly on all my targets, including LIN64, but
    more importantly (in practice, 64-bit Linux is a very rare target in my
    daily routine) just because it is shorter. And I don't care that it is
    formally "incorrect" on my more common targets. Or may be not
    "formally", but both gcc and clang think so.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Thu Jan 8 01:29:07 2026
    From Newsgroup: comp.lang.c

    On Wed, 07 Jan 2026 13:32:27 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Lawrence DrCOOliveiro <ldo@nz.invalid> writes:
    On Wed, 7 Jan 2026 12:45:30 -0500, James Russell Kuyper Jr. wrote:
    On a different point, I used time_t as an example. It would have
    been better to use ptrdiff_t instead, since <inttypes.h> has a
    macro for that type, and doesn't have one for time_t.

    This is why you have configure scripts, so they can figure out the
    right types to use for building on your platform.

    I don't follow. ptrdiff_t is defined in <stddef.h>, and is the
    correct type for the result of subtracting two pointers. What
    relevant information would a configure script give you?

    configure scripts are a cornerstone of software development religion for
    quite a few people.
    I hate them (scripts, not people) with passion.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Jan 7 16:00:19 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 07 Jan 2026 13:28:45 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence D|ore4raoOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    don|ore4raot have to hard-code assumptions about the lengths of
    integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.

    In the quoted paragraph above, Michael wrote about using %u to print
    unsigned long, not about using %u to print some type hidden behind
    a typedef. If he didn't mean that, he can say so.

    But even if he meant to talk about printing, say, uint64_t values,
    my point stands.

    I wouldn't define my own "uint64" type. I'd just use "uint64_t",
    defined in <stdint.h>. And I'd use one of several *correct* ways
    to print uint64_t values.

    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same width
    on the current implementation), do you really prefer the version
    marked as "incorrect"?

    I hoped that I already clarified that point more than one time.
    Obviously, I hoped wrong.

    And you still haven't. I asked a specific question above. What is
    your answer? Would you use a "%u" format to print a value that's
    defined with type unsigned long? I inferred from what you wrote
    that your answer would be yes. If your answer is no, I'll gladly
    accept that. (And if so, what you wrote previously was unclear,
    but I'm not going to worry about that if you clarify what you meant)

    You've previously indicated that you find "%lu" uglier than "%u",
    and that that's relevant to which one you would use. Do you still
    think so?

    I would appreciate direct yes or no answers to both of those
    questions.

    In the case I am talking about n declared as uint32_t.
    uint32_t is an alias of 'unsigned long' on 32-bit embedded targets, on
    32-bit Linux, on 32-bit Windows and on 64-bit Windows. It is
    alias of 'unsigned int' on 64-bit Linux.
    Sometimes I move code between targets by myself, sometimes, rarely,
    other people do it. I don't want to have different versions of the code
    and I don't want to use ugly standard specifiers. Between two pretty
    and working variants I prefer the shorter one. Partly because it is guaranteed to work correctly on all my targets, including LIN64, but
    more importantly (in practice, 64-bit Linux is a very rare target in my
    daily routine) just because it is shorter. And I don't care that it is formally "incorrect" on my more common targets. Or may be not
    "formally", but both gcc and clang think so.

    So you'd write code that happens to work on some implementations rather
    than code that's correct on all implementations.

    You know that unsigned long is at least 32 bits wide, and therefore that converting a uint32_t value to unsigned long will not lose information,
    and therefore that

    uint32_t x = 42;
    printf("%lu\n", (unsigned long)x);

    will work correctly. You can do this without using the ugly
    <inttypes.h> macros. Why wouldn't you?

    Sure, you can write code that happens to work on the only implementation
    you care about, but in my opinion, aside from being dangerous, it's just
    too much work. I don't care whether uint32_t is defined as unsigned int
    or unsigned long on a particular implementation, and I don't have to care.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Thu Jan 8 02:38:46 2026
    From Newsgroup: comp.lang.c

    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 07 Jan 2026 13:28:45 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence D|ore4raoOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    don|ore4raot have to hard-code assumptions about the lengths of
    integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences,
    like in case of using %u to print 'unsigned long' on target
    with 32-bit longs, or like using %llu to print 'unsigned long'
    on target with 64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.

    In the quoted paragraph above, Michael wrote about using %u to
    print unsigned long, not about using %u to print some type hidden
    behind a typedef. If he didn't mean that, he can say so.

    But even if he meant to talk about printing, say, uint64_t values,
    my point stands.

    I wouldn't define my own "uint64" type. I'd just use "uint64_t",
    defined in <stdint.h>. And I'd use one of several *correct* ways
    to print uint64_t values.

    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same
    width on the current implementation), do you really prefer the
    version marked as "incorrect"?

    I hoped that I already clarified that point more than one time.
    Obviously, I hoped wrong.

    And you still haven't. I asked a specific question above. What is
    your answer? Would you use a "%u" format to print a value that's
    defined with type unsigned long? I inferred from what you wrote
    that your answer would be yes. If your answer is no, I'll gladly
    accept that. (And if so, what you wrote previously was unclear,
    but I'm not going to worry about that if you clarify what you meant)

    When n declared as 'unsigned long' derectly rather than via unint32_t
    alias than the answer is 'no'.
    You've previously indicated that you find "%lu" uglier than "%u",
    and that that's relevant to which one you would use. Do you still
    think so?

    I would appreciate direct yes or no answers to both of those
    questions.

    It depends on how n declared.
    When it declared as 'unsigned long' then "lu" is not uglier.
    When it is defined as uint32_t it is uglier, despite the fact that on
    absolute majority of the targets that I care about the latter is an
    alias of the former.
    In the case I am talking about n declared as uint32_t.
    uint32_t is an alias of 'unsigned long' on 32-bit embedded targets,
    on 32-bit Linux, on 32-bit Windows and on 64-bit Windows. It is
    alias of 'unsigned int' on 64-bit Linux.
    Sometimes I move code between targets by myself, sometimes, rarely,
    other people do it. I don't want to have different versions of the
    code and I don't want to use ugly standard specifiers. Between two
    pretty and working variants I prefer the shorter one. Partly
    because it is guaranteed to work correctly on all my targets,
    including LIN64, but more importantly (in practice, 64-bit Linux is
    a very rare target in my daily routine) just because it is shorter.
    And I don't care that it is formally "incorrect" on my more common
    targets. Or may be not "formally", but both gcc and clang think so.


    So you'd write code that happens to work on some implementations
    rather than code that's correct on all implementations.

    No, it is correct on all implementation. Idea that in C, as opposed to
    C++, two unsigned integer types of the same size are somehow
    different is, IMHO, an abomination. And that is one not especially
    common case in which I don't care about opinion of the Standard.
    You know that unsigned long is at least 32 bits wide, and therefore
    that converting a uint32_t value to unsigned long will not lose
    information, and therefore that

    uint32_t x = 42;
    printf("%lu\n", (unsigned long)x);

    will work correctly. You can do this without using the ugly
    <inttypes.h> macros. Why wouldn't you?

    If it was named 'ulong' I'd seriously consider such solution. But when
    the name of type is not just rather long, but consists of two words as
    well, I wouldn't do it.
    Sure, you can write code that happens to work on the only
    implementation you care about, but in my opinion, aside from being
    dangerous, it's just too much work. I don't care whether uint32_t is
    defined as unsigned int or unsigned long on a particular
    implementation, and I don't have to care.

    I also don't care. Since for more than decade* I didn't have target
    with 'int' shorter than 32 bits, I just use %u. It takes me zero
    thinking.
    BTW, I am always aware of exact sizes of the basic types of the target
    that I work on. I don't feel comfotable without such knowledge. That
    how my mind works. It has problems with too abstract abstractions.
    ------
    * - or may be a little less than decade, I don't remember in which year
    exactly I did last change to project that runs on TI C2000, which is
    32-bit CPU, BTW, but TI being TI still had size of int that they
    had chosen.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Jan 7 17:36:34 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 07 Jan 2026 13:28:45 -0800
    [...]
    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same
    width on the current implementation), do you really prefer the
    version marked as "incorrect"?

    I hoped that I already clarified that point more than one time.
    Obviously, I hoped wrong.

    And you still haven't. I asked a specific question above. What is
    your answer? Would you use a "%u" format to print a value that's
    defined with type unsigned long? I inferred from what you wrote
    that your answer would be yes. If your answer is no, I'll gladly
    accept that. (And if so, what you wrote previously was unclear,
    but I'm not going to worry about that if you clarify what you meant)

    When n declared as 'unsigned long' derectly rather than via unint32_t
    alias than the answer is 'no'.

    Thank you for answering that.

    You've previously indicated that you find "%lu" uglier than "%u",
    and that that's relevant to which one you would use. Do you still
    think so?

    I would appreciate direct yes or no answers to both of those
    questions.

    It depends on how n declared.
    When it declared as 'unsigned long' then "lu" is not uglier.
    When it is defined as uint32_t it is uglier, despite the fact that on absolute majority of the targets that I care about the latter is an
    alias of the former.

    Let me see if I understand you correctly.

    uint32_t n = 42;
    printf("%u\n", n);
    printf("%lu\n", n);

    In this context, you find "%lu" uglier than "%u"?

    [SNIP]
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Thu Jan 8 11:01:44 2026
    From Newsgroup: comp.lang.c

    On Wed, 07 Jan 2026 17:36:34 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    Let me see if I understand you correctly.

    uint32_t n = 42;
    printf("%u\n", n);
    printf("%lu\n", n);

    In this context, you find "%lu" uglier than "%u"?


    Yes.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Jan 8 11:35:27 2026
    From Newsgroup: comp.lang.c

    On 08/01/2026 00:26, Michael S wrote:
    On Wed, 07 Jan 2026 13:28:45 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-06 04:29, Michael S wrote:
    On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)
    Lawrence D|ore4raoOliveiro <ldo@nz.invalid> wrote:
    ...
    Section 7.8 of the C spec defines macros you can use so you
    don|ore4raot have to hard-code assumptions about the lengths of >>>>>>>> integers in printf-format strings.

    Did you ever try to use them? They look ugly.

    Which is more important, correctness or beauty?

    It depends.

    When I know for sure that incorrectness has no consequences, like
    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on target with
    64-bit longs, then beauty wins. Easily.

    Seriously?

    An example:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    Are you really saying that the second version is so much uglier
    than the first that you'd rather write incorrect code?

    I suspect he may have been referring to code that needs
    to build for both 32-bit and 64-bit targets. One might
    typedef 'uint64' to be unsigned long long on both targets
    and just use %llu for the format string. BTDT.

    In the quoted paragraph above, Michael wrote about using %u to print
    unsigned long, not about using %u to print some type hidden behind
    a typedef. If he didn't mean that, he can say so.

    But even if he meant to talk about printing, say, uint64_t values,
    my point stands.

    I wouldn't define my own "uint64" type. I'd just use "uint64_t",
    defined in <stdint.h>. And I'd use one of several *correct* ways
    to print uint64_t values.

    Michael, if you'd care to clarify, given:

    unsigned long n = 42;
    printf("%u\n", n); // incorrect
    printf("%lu\n", n); // correct

    (and assuming that unsigned int and unsigned long are the same width
    on the current implementation), do you really prefer the version
    marked as "incorrect"?


    I hoped that I already clarified that point more than one time.
    Obviously, I hoped wrong.

    In the case I am talking about n declared as uint32_t.
    uint32_t is an alias of 'unsigned long' on 32-bit embedded targets, on
    32-bit Linux, on 32-bit Windows and on 64-bit Windows. It is
    alias of 'unsigned int' on 64-bit Linux.

    "uint32_t" is an alias of "unsigned long" in the common embedded ABI for 32-bit ARM, as used by gcc and clang. I haven't tested if it is the
    same on the five other 32-bit proprietary ARM compilers I know of (IAR,
    GHS, Metrowerks, ImageCraft, ARM/Keil), and there are no doubt many
    other ARM compilers I have not heard of. I think I have used perhaps
    seven other 32-bit embedded processor architectures at least
    occasionally, and can probably think of a maybe another ten that I have
    never used. And there are many more.

    I think it would be extraordinarily arrogant of me to claim I know that "uint32_t is unsigned long on 32-bit embedded targets". Do you have
    such a wide experience that /you/ can justify that claim?

    Indeed, a quick check using godbolt.org shows that on 32-bit ARM Linux, uint32_t is "unsigned int", and for other 32-bit targets there is a mixture.

    Sometimes I move code between targets by myself, sometimes, rarely,
    other people do it. I don't want to have different versions of the code
    and I don't want to use ugly standard specifiers. Between two pretty
    and working variants I prefer the shorter one. Partly because it is guaranteed to work correctly on all my targets, including LIN64, but
    more importantly (in practice, 64-bit Linux is a very rare target in my
    daily routine) just because it is shorter. And I don't care that it is formally "incorrect" on my more common targets. Or may be not
    "formally", but both gcc and clang think so.


    This seems like a fine example of cutting off your own nose to spite
    your face. The single worst feature (IMHO) of printf and friends is
    that you have to match up the format string with the parameters and
    their types, or you have UB. Thus most compilers and static checkers
    can check literal format strings and the compare them to the number and
    types of the parameters. Warnings like gcc's "-Wformat" turn one of C's biggest static checking holes into almost a non-issue for many cases.
    And you throw that out just because you think "%lu" is uglier than "%u".

    I've been working with embedded C development for 30+ years. And I find
    that embedded C developers fall into two categories - those that use
    compiler warnings as obsessively as practically possible, and those that
    write crappy code with glaring errors. That division is almost
    independent of experience - people who have been in the branch for
    decades make mistakes too.


    I don't think you will find anyone who will tell you "PRIu32" and
    friends are nice and neat, and look good in a string literal. And if
    you are writing code that does not have to be portable (most code does
    not), I see nothing wrong with using "%lu" for uint32_t if you know your platform makes it an unsigned long int. Or you can, as others have
    suggested, use "%u" and cast your uint32_t to "unsigned" (or "%lu" and "unsigned long", or whatever makes sense to you). If you have a modern
    enough C library, you can use "%w32u" for uint32_t. Or you can use your
    own specific functions (very common in the embedded world - "printf" has
    a /lot/ overhead), or variadic and _Generic macros to get type-safe
    printing. There are many possibilities of doing this right (where
    "right" depends on your balances between convenience and portability) -
    there is no justification that I can see for doing it wrong.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Jan 8 17:13:21 2026
    From Newsgroup: comp.lang.c

    On 07/01/2026 02:14, bart wrote:
    On 07/01/2026 00:44, James Kuyper wrote:
    On 2026-01-06 13:05, Michael S wrote:

    in case of using %u to print 'unsigned long' on target with 32-bit
    longs, or like using %llu to print 'unsigned long' on-a target with
    64-bit longs, then beauty wins. Easily.

    You've got it backwards. "%u" is the correct specifier to use for
    unsigned long on all platforms, whether unsigned long is 32, 36, or even
    48 bits.

    So not "%lu"?



    "%lu" is, as you point out, the correct specifier for "unsigned long".

    James made a mistake here - it's unusual for him, but we are all
    fallible. That is why it is a good idea to enable whatever static
    warnings you can get from a compiler, as long as they don't conflict
    with your particular coding style. And that is why it is madness for
    Michael to disable something as useful as printf format checking just
    because he thinks "%lu" is "ugly".

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Thu Jan 8 09:54:34 2026
    From Newsgroup: comp.lang.c

    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-07 08:06, Tim Rentsch wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named types or >>>>> typedefs for with there is a corresponding printf() specifier, you
    should use that specifier. Otherwise, if you know that an expression >>>>> has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    Really? What passage in the C standard is being paraphrased?

    This is advice, not paraphrased text from the C standard. [...]

    I was responding to Scotty Lurndal's statement that the C
    standard was being paraphrased (by someone, it didn't matter to
    me who). I don't care about whether his statement is true; my
    interest is only in what part of the C standard he thinks is
    being paraphrased. He is in a position to answer that question,
    and more to the point he is the only person who is.

    Unrelated matter: a couple of your recent postings show a name
    change to a longer form of your name. I don't know what might
    have prompted that change, but for what it's worth I like the
    earlier shorter form better, if only for consistency with
    earlier postings.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Thu Jan 8 10:08:24 2026
    From Newsgroup: comp.lang.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-07 08:06, Tim Rentsch wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    I was responding to Scotty Lurndal's statement that the C

    Sorry, Scott Lurndal. My bad.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c on Thu Jan 8 18:36:42 2026
    From Newsgroup: comp.lang.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-07 08:06, Tim Rentsch wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named types or >>>>>> typedefs for with there is a corresponding printf() specifier, you >>>>>> should use that specifier. Otherwise, if you know that an expression >>>>>> has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    Really? What passage in the C standard is being paraphrased?

    This is advice, not paraphrased text from the C standard. [...]

    I was responding to Scotty Lurndal's statement that the C
    standard was being paraphrased (by someone, it didn't matter to
    me who). I don't care about whether his statement is true; my
    interest is only in what part of the C standard he thinks is
    being paraphrased. He is in a position to answer that question,
    and more to the point he is the only person who is.

    It's pretty clear that the standard describes the printf
    function and the methods used to match the format characters
    to the data types of the arguments. The fact that James
    framed that as advice doesn't change interpretation of
    the text of the standard, whether or not you consider
    that to be a paraphrase.


    "The main rules for paraphrasing are to fully understand
    the original text, restate its core idea in your own words
    and sentence structure, use synonyms, and always cite the
    original source to avoid plagiarism, even if the wording is different.

    And it is spelled "Scott".

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Thu Jan 8 13:05:23 2026
    From Newsgroup: comp.lang.c

    scott@slp53.sl.home (Scott Lurndal) writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-07 08:06, Tim Rentsch wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named
    types or typedefs for with there is a corresponding printf()
    specifier, you should use that specifier. Otherwise, if you
    know that an expression has one of the types declared in
    <stdint.h>, you should use the corresponding macro #defined in
    <inttypes.h> to print it.

    I should? Really?
    Sorry, James, but you have no authority to make such statements.

    James is paraphrasing the C standard.

    Really? What passage in the C standard is being paraphrased?

    This is advice, not paraphrased text from the C standard. [...]

    I was responding to Scotty Lurndal's statement that the C
    standard was being paraphrased (by someone, it didn't matter to
    me who). I don't care about whether his statement is true; my
    interest is only in what part of the C standard he thinks is
    being paraphrased. He is in a position to answer that question,
    and more to the point he is the only person who is.

    It's pretty clear that the standard describes the printf
    function and the methods used to match the format characters
    to the data types of the arguments. The fact that James
    framed that as advice doesn't change interpretation of
    the text of the standard, whether or not you consider
    that to be a paraphrase.


    "The main rules for paraphrasing are to fully understand the
    original text, restate its core idea in your own words and
    sentence structure, use synonyms, and always cite the original
    source to avoid plagiarism, even if the wording is different.

    I see where the C standard says the macros in inttypes.h are
    suitable for use with printf (and scanf). That isn't at all
    the same as saying people should use them. Just because
    something can be done doesn't mean it should be done. James's
    statement "you should use the corresponding macro" is not a
    paraphrase, it's a statement of his opinion.

    And it is spelled "Scott".

    Yes, that was an inadvertent typo, and I had already posted
    a correction.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Thu Jan 8 19:16:19 2026
    From Newsgroup: comp.lang.c

    On 2026-01-07 16:32, Keith Thompson wrote:
    Lawrence DrCOOliveiro <ldo@nz.invalid> writes:
    On Wed, 7 Jan 2026 12:45:30 -0500, James Russell Kuyper Jr. wrote:
    On a different point, I used time_t as an example. It would have
    been better to use ptrdiff_t instead, since <inttypes.h> has a macro
    for that type, and doesn't have one for time_t.

    This is why you have configure scripts, so they can figure out the
    right types to use for building on your platform.

    I don't follow. ptrdiff_t is defined in <stddef.h>, and is the correct
    type for the result of subtracting two pointers. What relevant
    information would a configure script give you?

    I suspect he's referring to time_t, not ptrdiff_t. I mentioned the
    absence of a macro #defined in <inttypes.h> as a reason why I should not
    have used time_t as an example.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Thu Jan 8 19:31:13 2026
    From Newsgroup: comp.lang.c

    On 2026-01-07 19:38, Michael S wrote:
    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    So you'd write code that happens to work on some implementations
    rather than code that's correct on all implementations.


    No, it is correct on all implementation. Idea that in C, as opposed to
    C++, two unsigned integer types of the same size are somehow
    different is, IMHO, an abomination. And that is one not especially
    common case in which I don't care about opinion of the Standard.

    We're not talking about two unsigned integer types with same size. We're talking about unsigned long, which can be any size >= 32 bits, and
    uint32_t, which can only be exactly 32 bits. Your code is NOT portable
    to a platform where unsigned long is greater than 32 bits.

    ...
    I also don't care. Since for more than decade* I didn't have target
    with 'int' shorter than 32 bits, I just use %u. It takes me zero
    thinking.

    As a general rule, I find that people who claim a decision requires no
    thought generally are referring to a decision that should have been made differently if sufficient thought had been put into it. This is a prime example.

    BTW, I am always aware of exact sizes of the basic types of the target
    that I work on. I don't feel comfotable without such knowledge. That
    how my mind works. It has problems with too abstract abstractions.

    I'd have no problem with your approach if you hadn't falsely claimed
    that "It is correct on all platforms". There's nothing wrong with code
    that is intentionally platform specific. Platform-specific code that the author incorrectly believes to be "correct on all platforms" is a problem.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Fri Jan 9 09:25:16 2026
    From Newsgroup: comp.lang.c

    On 08/01/2026 01:38, Michael S wrote:

    No, it is correct on all implementation. Idea that in C, as opposed to
    C++, two unsigned integer types of the same size are somehow
    different is, IMHO, an abomination. And that is one not especially
    common case in which I don't care about opinion of the Standard.

    You can have the opinion that any two integer types of the same size
    /should/ be fully interchangeable in C. That's a reasonable opinion,
    and you are not the only one to think that way.

    But the C language is defined differently. There are a number of
    situations where different integer types have the same size (and range
    and representation), yet are different types. On most 32-bit platforms, "long" is the same size as either "int" or "long long". But it is not type-compatible with either. "uint32_t" will probably be an alias for
    either "unsigned int" or "unsigned long" (but could on some platforms be
    an alias for "unsigned char", "char", "unsigned short", or an extended
    integer type).

    It does not really matter if you think the C language works the way you
    would like it to - when you program in C, the C standard is the contract between you and the compiler. We all have aspects of C that we dislike,
    and I am sure the same applies to compiler writers, but we all agree to
    stick to a common definition of the language. If you try to code in
    some C-like language that works the way /you/ would like it to, you will
    run into trouble when the compiler interprets your code differently from
    how you had intended.

    Use the types as the standard specifies. If the standard says "use %lu
    for this type, and %u for that type", then do that. If the standard
    says "pointers to unsigned int are incompatible with pointers to
    unsigned long, even if the integer types are the same size", then don't
    mix such pointer types. It's not that hard. Yes, occasionally it can
    be a little inconvenient or "ugly", but writing correct code pays off.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Fri Jan 9 14:18:59 2026
    From Newsgroup: comp.lang.c

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-07 19:38, Michael S wrote:
    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    So you'd write code that happens to work on some implementations
    rather than code that's correct on all implementations.


    No, it is correct on all implementation. Idea that in C, as opposed
    to C++, two unsigned integer types of the same size are somehow
    different is, IMHO, an abomination. And that is one not especially
    common case in which I don't care about opinion of the Standard.

    We're not talking about two unsigned integer types with same size.
    We're talking about unsigned long, which can be any size >= 32 bits,
    and uint32_t, which can only be exactly 32 bits. Your code is NOT
    portable to a platform where unsigned long is greater than 32 bits.


    I don't know how you came to discussions of what is possible.
    My statement was concrete. It was about platforms like Windows (of all
    flavors) and 2-3 specific 32-bit embedded targets that I currently
    care about.
    On all these platforms uint32_t is alias of 'unsigned long' which is
    32-bit wide. 'unsigned int' is also 32-bit wide.
    I claim that *on these platforms* uint32_t and 'unsigned int' are *not* different types. I don't care to what the Standard says about it.
    I do care about what gcc says about it because I am annoyed by warnings
    that I consider pointless.

    Printing uint32_t values on these platforms with %u specifier, apart
    from advantage of being shorter, has advantage of being undoubtedly
    correct on LIN64. Unlike printing with %lu.

    Now, going one step further and using more intimate knowledge of SysV
    ABI I can argue with myself and prove (could I? I am only 95% sure)
    that on LIN64 %lu will also always print correct result. But I don't
    want to take this step.

    ...
    I also don't care. Since for more than decade* I didn't have target
    with 'int' shorter than 32 bits, I just use %u. It takes me zero
    thinking.

    As a general rule, I find that people who claim a decision requires
    no thought generally are referring to a decision that should have
    been made differently if sufficient thought had been put into it.
    This is a prime example.

    BTW, I am always aware of exact sizes of the basic types of the
    target that I work on. I don't feel comfotable without such
    knowledge. That how my mind works. It has problems with too
    abstract abstractions.

    I'd have no problem with your approach if you hadn't falsely claimed
    that "It is correct on all platforms".

    Which I didn't.

    There's nothing wrong with
    code that is intentionally platform specific. Platform-specific code
    that the author incorrectly believes to be "correct on all platforms"
    is a problem.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Fri Jan 9 13:49:51 2026
    From Newsgroup: comp.lang.c

    On 09/01/2026 13:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-07 19:38, Michael S wrote:
    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    So you'd write code that happens to work on some implementations
    rather than code that's correct on all implementations.


    No, it is correct on all implementation. Idea that in C, as opposed
    to C++, two unsigned integer types of the same size are somehow
    different is, IMHO, an abomination. And that is one not especially
    common case in which I don't care about opinion of the Standard.

    We're not talking about two unsigned integer types with same size.
    We're talking about unsigned long, which can be any size >= 32 bits,
    and uint32_t, which can only be exactly 32 bits. Your code is NOT
    portable to a platform where unsigned long is greater than 32 bits.


    I don't know how you came to discussions of what is possible.
    My statement was concrete. It was about platforms like Windows (of all flavors) and 2-3 specific 32-bit embedded targets that I currently
    care about.
    On all these platforms uint32_t is alias of 'unsigned long' which is
    32-bit wide. 'unsigned int' is also 32-bit wide.
    I claim that *on these platforms* uint32_t and 'unsigned int' are *not* different types. I don't care to what the Standard says about it.

    Of course they are different types. In C, "unsigned int" and "unsigned
    long" are different types. The standard says so - and it is the
    standard that defines the language.

    I do care about what gcc says about it because I am annoyed by warnings
    that I consider pointless.

    The warnings are not pointless, despite what you might think. And of
    course gcc is not going to modify its warnings to pander to someone who
    has their own personal ideas about what C should be. We /all/ have
    ideas about how C could be better for our own needs. But outside the
    realm of personal languages where the single user also designed the
    language and wrote the compiler, you have to work with the language as
    it is defined.

    For a clear example of the differences between unsigned int and unsigned
    long, look at the generated code here:

    <https://godbolt.org/z/hdjz6Y7vY>

    That is for embedded 32-bit ARM, where "uint32_t" is "unsigned long",
    and is the same size as "unsigned int". Then try swapping the compiler
    to the 32-bit ARM gcc Linux version - here "uint32_t" is "unsigned int",
    and again the same size as "unsigned long". Look at the differences in
    the code.

    It doesn't matter if /you/ think that all 32-bit integer types should be
    the same - in C, they are not. And therefore in C compilers, they are
    not the same.


    Printing uint32_t values on these platforms with %u specifier, apart
    from advantage of being shorter, has advantage of being undoubtedly
    correct on LIN64. Unlike printing with %lu.

    But printing uint32_t with "%u" on 32-bit EABI ARM is not correct - it
    is UB. It will /probably/ work, but maybe some day you will come across
    a situation where it will not.

    I have a lot of trouble understanding why you would go out of your way
    to knowingly write incorrect code - prioritising tiny, irrelevant
    savings in source code space over correct, guaranteed, portable code
    that can be automatically checked by tools.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From wij@wyniijj5@gmail.com to comp.lang.c on Sat Jan 10 00:17:36 2026
    From Newsgroup: comp.lang.c

    On Fri, 2026-01-09 at 13:49 +0100, David Brown wrote:
    On 09/01/2026 13:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-07 19:38, Michael S wrote:
    On Wed, 07 Jan 2026 16:00:19 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    So you'd write code that happens to work on some implementations rather than code that's correct on all implementations.
    -a

    No, it is correct on all implementation. Idea that in C, as opposed
    to C++, two unsigned integer types of the same size are somehow different is, IMHO, an abomination. And that is one not especially common case in which I don't care about opinion of the Standard.

    We're not talking about two unsigned integer types with same size.
    We're talking about unsigned long, which can be any size >= 32 bits,
    and uint32_t, which can only be exactly 32 bits. Your code is NOT portable to a platform where unsigned long is greater than 32 bits.


    I don't know how you came to discussions of what is possible.
    My statement was concrete. It was about platforms like Windows (of all flavors) and 2-3 specific 32-bit embedded targets that I currently
    care about.
    On all these platforms uint32_t is alias of 'unsigned long' which is
    32-bit wide. 'unsigned int' is also 32-bit wide.
    I claim that *on these platforms* uint32_t and 'unsigned int' are *not* different types. I don't care to what the Standard says about it.

    Of course they are different types.-a In C, "unsigned int" and "unsigned long" are different types.-a The standard says so - and it is the
    standard that defines the language.

    I do care about what gcc says about it because I am annoyed by warnings that I consider pointless.

    The warnings are not pointless, despite what you might think.-a And of course gcc is not going to modify its warnings to pander to someone who
    has their own personal ideas about what C should be.-a We /all/ have
    ideas about how C could be better for our own needs.-a But outside the
    realm of personal languages where the single user also designed the
    language and wrote the compiler, you have to work with the language as
    it is defined.

    For a clear example of the differences between unsigned int and unsigned long, look at the generated code here:

    <https://godbolt.org/z/hdjz6Y7vY>

    That is for embedded 32-bit ARM, where "uint32_t" is "unsigned long",
    and is the same size as "unsigned int".-a Then try swapping the compiler
    to the 32-bit ARM gcc Linux version - here "uint32_t" is "unsigned int",
    and again the same size as "unsigned long".-a Look at the differences in
    the code.

    It doesn't matter if /you/ think that all 32-bit integer types should be
    the same - in C, they are not.-a And therefore in C compilers, they are
    not the same.


    Printing uint32_t values on these platforms with %u specifier, apart
    from advantage of being shorter, has advantage of being undoubtedly
    correct on LIN64. Unlike printing with %lu.

    But printing uint32_t with "%u" on 32-bit EABI ARM is not correct - it
    is UB.-a It will /probably/ work, but maybe some day you will come across
    a situation where it will not.

    I have a lot of trouble understanding why you would go out of your way
    to knowingly write incorrect code - prioritising tiny, irrelevant
    savings in source code space over correct, guaranteed, portable code
    that can be automatically checked by tools.
    Snipet from ClassGuidelines.txt
    ...
    wrd(or notation)
    This function converts the argument object (a type, class,..) to text
    which can be used to construct the 'same' (including verified by
    operator==) object.
    Note: This function is not mandatory. But in OO design, the text
    may include the description of interactions between external
    events and sub-classes. This would form the basic proof of
    correctness of concept.
    My reply might not be directly in the topic of current post. Just jumpped in
    to reply. It looks to me the format character MUST match the type passed to-a printf, otherwise UB.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c on Fri Jan 9 16:26:50 2026
    From Newsgroup: comp.lang.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    scott@slp53.sl.home (Scott Lurndal) writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:


    I was responding to Scotty Lurndal's statement that the C
    standard was being paraphrased (by someone, it didn't matter to
    me who). I don't care about whether his statement is true; my
    interest is only in what part of the C standard he thinks is
    being paraphrased. He is in a position to answer that question,
    and more to the point he is the only person who is.

    It's pretty clear that the standard describes the printf
    function and the methods used to match the format characters
    to the data types of the arguments. The fact that James
    framed that as advice doesn't change interpretation of
    the text of the standard, whether or not you consider
    that to be a paraphrase.


    "The main rules for paraphrasing are to fully understand the
    original text, restate its core idea in your own words and
    sentence structure, use synonyms, and always cite the original
    source to avoid plagiarism, even if the wording is different.

    I see where the C standard says the macros in inttypes.h are
    suitable for use with printf (and scanf). That isn't at all
    the same as saying people should use them.

    Why on earth would the put them there if they didn't expect
    them to be used?

    Just because
    something can be done doesn't mean it should be done.

    Sigh.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Fri Jan 9 11:27:34 2026
    From Newsgroup: comp.lang.c

    wij <wyniijj5@gmail.com> writes:
    On Fri, 2026-01-09 at 13:49 +0100, David Brown wrote:
    [...]
    I have a lot of trouble understanding why you would go out of your way
    to knowingly write incorrect code - prioritising tiny, irrelevant
    savings in source code space over correct, guaranteed, portable code
    that can be automatically checked by tools.

    Snipet from ClassGuidelines.txt
    ...
    wrd(or notation)
    This function converts the argument object (a type, class,..) to text
    [SNIP]

    My reply might not be directly in the topic of current post. Just jumpped in to reply.

    Huh?? "ClassGuideline.txt" (which I managed to find on Sourceforge)
    is a set of guidelines for C++ programming, apparently something
    you wrote. As far as I can tell, it has nothing to do with the
    current discussion or with the topic of this newsgroup. Why did
    you mention it here?

    It looks to me the format character MUST match the type passed to-a printf, otherwise UB.

    It doesn't just look to you that way. The C standard says
    so explicitly. C17 and earlier says "If any argument is not
    the correct type for the corresponding conversion specification,
    the behavior is undefined." C23 changed the wording, saying that
    fprintf shall behave as if it uses va_arg; the description of va_arg
    says the behavior is undefined if the wrong type is used.

    Note that the description of va_arg allows, for example, using
    unsigned int for an argument of type int or vice versa *if* the
    value is within the range of both. If it had been the intent to
    allow incompatible types that happen to have the same size and
    representation, the standard would have said so.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Sat Jan 10 22:02:03 2026
    From Newsgroup: comp.lang.c

    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely claimed
    that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From James Russell Kuyper Jr.@jameskuyper@alumni.caltech.edu to comp.lang.c on Sat Jan 10 22:40:46 2026
    From Newsgroup: comp.lang.c

    On 2026-01-08 13:36, Scott Lurndal wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> writes:

    On 2026-01-07 08:06, Tim Rentsch wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 6 Jan 2026 10:31:41 -0500
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    If you know that an expression has one of the standard-named types or >>>>>>> typedefs for with there is a corresponding printf() specifier, you >>>>>>> should use that specifier. Otherwise, if you know that an expression >>>>>>> has one of the types declared in <stdint.h>, you should use the
    corresponding macro #defined in <inttypes.h> to print it.
    ...
    James is paraphrasing the C standard.
    ...
    It's pretty clear that the standard describes the printf
    function and the methods used to match the format characters
    to the data types of the arguments. The fact that James
    framed that as advice doesn't change interpretation of
    the text of the standard, whether or not you consider
    that to be a paraphrase.

    I was advising against the practice of finding out what type uint32_t is
    a typedef for on the implementation you're currently using, and using
    the corresponding format specifier rather than the appropriate
    <inttypes.h> macro. For any given implementation, those will both work
    equally well, and nothing the standard says favors one over the other.
    It is the fact that I have, for most of my career, been required to
    produce highly portable code, which makes me prefer the ugly macros over
    the simpler specifiers. That is not, in any sense, a paraphrase of
    anything said in the standard. It is a deduction from what the standard
    says, applied to my particular working environment.

    What I didn't notice when I made my original comment is that he wasn't
    even using the appropriate format specifier, which would have been %lu,
    but %u, simply because, on the platform he was using, they happened to
    work equally well.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Sun Jan 11 13:20:15 2026
    From Newsgroup: comp.lang.c

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.


    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b) (see
    below) printing variables declared as uint32_t via %u is probably UB
    according to the Standard (I don't know for sure, however it is
    probable), but it can't cause troubles with production C compiler. Or
    with any C compiler that is made in intention of being used rather than
    crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    I never claimed that it is good idea on targets with 'unsigned int'
    that is narrower.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Sun Jan 11 04:59:47 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b) (see below) printing variables declared as uint32_t via %u is probably UB according to the Standard (I don't know for sure, however it is
    probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)

    If uint32_t and unsigned long have different sizes, it still might
    happen happen to "work", depending on calling conventions. Passing a
    32-bit argument and telling printf to expect a 64-bit value clearly has undefined behavior, but perhaps both happen to be passed in 64-bit
    registers, for example.

    but it can't cause troubles with production C compiler. Or
    with any C compiler that is made in intention of being used rather than crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'

    Not guaranteed by the language (and not true on the implementations
    I use most often).

    b) 'unsigned int' is at least 32-bit wide.

    Not guaranteed by the language (though it happens to be guaranteed by
    POSIX).

    I never claimed that it is good idea on targets with 'unsigned int'
    that is narrower.

    I claim that it's not a good idea on any target.

    I find it *much* easier to write portable code than to spend time
    figuring out what non-portable code will happens to work on the
    platforms I happen to care about today.

    uint32_t n = 42;
    printf("%lu\n", (unsigned long)n);

    unsigned long is guaranteed by the language to be at least 32 bits.
    The conversion is guaranteed not to lose information. The format
    matches the type of the argument. And the code will work correctly
    on any conforming hosted implementation. (It might involve an
    unnecessary 32 to 64 bit conversion, but given the overhead of
    printf, that's unlikely to be a problem -- and if it is, I can use
    the appropriate macro from <inttypes.h>.)

    And to my eyes, using "%u" with a uint32_t argument is *ugly*.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Sun Jan 11 15:32:01 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)


    What exactly, assuming that conditions (a) and (b) fulfilled, should implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    If uint32_t and unsigned long have different sizes, it still might
    happen happen to "work", depending on calling conventions. Passing a
    32-bit argument and telling printf to expect a 64-bit value clearly
    has undefined behavior, but perhaps both happen to be passed in 64-bit registers, for example.


    And that is sort of intimate knowledge of the ABI that I don't want to
    exploit, as already mentioned in my other post in this sub-thread.

    but it can't cause troubles with production C compiler.
    Or with any C compiler that is made in intention of being used
    rather than crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'

    Not guaranteed by the language (and not true on the implementations
    I use most often).


    Did I ever say that it is guaranteed by the language or that it is
    universal in any other way?
    Normally you have much better reading comprehension than one that you demonstrate in this discussion. I'd guess that it's because I somehow
    caused you to become angry.

    b) 'unsigned int' is at least 32-bit wide.

    Not guaranteed by the language (though it happens to be guaranteed by
    POSIX).


    Did I ever say etc ...

    I never claimed that it is good idea on targets with 'unsigned int'
    that is narrower.

    I claim that it's not a good idea on any target.

    I find it *much* easier to write portable code than to spend time
    figuring out what non-portable code will happens to work on the
    platforms I happen to care about today.

    uint32_t n = 42;
    printf("%lu\n", (unsigned long)n);

    unsigned long is guaranteed by the language to be at least 32 bits.
    The conversion is guaranteed not to lose information. The format
    matches the type of the argument. And the code will work correctly
    on any conforming hosted implementation. (It might involve an
    unnecessary 32 to 64 bit conversion, but given the overhead of
    printf, that's unlikely to be a problem -- and if it is, I can use
    the appropriate macro from <inttypes.h>.)

    And to my eyes, using "%u" with a uint32_t argument is *ugly*.


    To be fair, it is not ideal.
    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient to
    use than standard macros and are equally good at carrying programmer's intentions.

    Microsoft has strong influence in committee, but was not able to push
    it into C11, where they successfully forced hands of other members on
    few much bigger and more controversial issues.
    I don't know what it means, May be, there is bold technical reason
    behind non-standardization of these size specifiers. Or may be there is
    no reason and Microsoft simply never tried.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Sun Jan 11 16:34:28 2026
    From Newsgroup: comp.lang.c

    On 11/01/2026 14:32, Michael S wrote:
    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    > No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)


    What exactly, assuming that conditions (a) and (b) fulfilled, should implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    If an architecture has 32-bit "unsigned long", then "unsigned int" is necessarily also 32-bit (since "unsigned int" is always at least 32-bit,
    and "unsigned long" cannot be smaller than "unsigned int"). The very
    fact that you listed "unsigned int is at least 32-bit wide" as an
    assumption shows you are not well versed with the basics of C standards
    in this area.

    I agree that it is difficult to imagine an implementation where
    "uint32_t" is "unsigned long" and where the code example you gave would
    not work as expected. But there are countless cases where C programmers
    have thought "it doesn't matter if this is UB, the compiler can't
    generate code other than the way I think it should". Could some future implementation on some future architecture do something I don't expect
    with the code example here? I am not willing to bet against that
    possibility - certainly not for something as petty as skipping a single
    letter in the source code.

    But to my mind, the prime disadvantage of writing this incorrect code
    (besides portability, which is not always a big concern) is that you
    block important and useful automated checks. That's just bad
    development practice. Don't worry about compiler maintainers getting
    fired for doing crazy things - worry about C programmers getting fired
    for doing crazy things. (I wouldn't immediately fire someone for
    writing code like this, but I'd reject it in a code review, and I'd have serious concerns about a programmer who knowingly wrote UB without
    vastly better justification than you have.)


    If uint32_t and unsigned long have different sizes, it still might
    happen happen to "work", depending on calling conventions. Passing a
    32-bit argument and telling printf to expect a 64-bit value clearly
    has undefined behavior, but perhaps both happen to be passed in 64-bit
    registers, for example.


    And that is sort of intimate knowledge of the ABI that I don't want to exploit, as already mentioned in my other post in this sub-thread.

    Writing code that is UB but "works as intended" /does/ require an and
    rely upon an intimate knowledge of the ABI. You are saying this works precisely because you know things about the ABI you are using. Writing correct code will keep it portable and working regardless of the ABI.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Sun Jan 11 18:19:45 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 16:34:28 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 11/01/2026 14:32, Michael S wrote:
    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    > No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)


    What exactly, assuming that conditions (a) and (b) fulfilled, should implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer immediately fired?

    If an architecture has 32-bit "unsigned long", then "unsigned int" is necessarily also 32-bit (since "unsigned int" is always at least
    32-bit,

    I am pretty sure that it is wrong.
    C Standard does not require for 'unsigned int' to be above 16 bits.

    and "unsigned long" cannot be smaller than "unsigned int").
    The very fact that you listed "unsigned int is at least 32-bit wide"
    as an assumption shows you are not well versed with the basics of C
    standards in this area.


    I am not well versed in the Standard. But in this particular case you
    are the one who doesn't know it.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Sun Jan 11 20:25:28 2026
    From Newsgroup: comp.lang.c

    On 11/01/2026 17:19, Michael S wrote:
    On Sun, 11 Jan 2026 16:34:28 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 11/01/2026 14:32, Michael S wrote:
    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    > No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)


    What exactly, assuming that conditions (a) and (b) fulfilled, should
    implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    If an architecture has 32-bit "unsigned long", then "unsigned int" is
    necessarily also 32-bit (since "unsigned int" is always at least
    32-bit,

    I am pretty sure that it is wrong.
    C Standard does not require for 'unsigned int' to be above 16 bits.


    Sorry, I jumbled that. It is unsigned long that must be at least 32
    bits, so your second requirement is not redundant.

    and "unsigned long" cannot be smaller than "unsigned int").
    The very fact that you listed "unsigned int is at least 32-bit wide"
    as an assumption shows you are not well versed with the basics of C
    standards in this area.


    I am not well versed in the Standard. But in this particular case you
    are the one who doesn't know it.


    I know it, but I still got it wrong here :-(

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Sun Jan 11 11:51:43 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    ...

    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...

    No, it is correct on all implementation.


    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b) (see below) printing variables declared as uint32_t via %u is probably UB according to the Standard (I don't know for sure, however it is
    probable), but it can't cause troubles with production C compiler. Or
    with any C compiler that is made in intention of being used rather than crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Sun Jan 11 11:58:47 2026
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    ...

    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...

    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b) (see
    below) printing variables declared as uint32_t via %u is probably UB
    according to the Standard (I don't know for sure, however it is
    probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    Very likely, but I don't think the C standard requires it. TTBOMU
    the C standard allows the possibility of an implementation where
    uint32_t is type distinct from any other nameable type, and yet
    the implementation could still be conforming.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Sun Jan 11 23:51:04 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 11:51:43 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:

    ...

    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...

    No, it is correct on all implementation.


    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable), but it can't cause troubles with
    production C compiler. Or with any C compiler that is made in
    intention of being used rather than crafted to prove theoretical
    points. Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?

    Four out of four target for which I write C programs for living in this
    decade:
    - Altera Nios2 (nios2-elf-gcc)
    - Arm Cortex-M bare metal (arm-none-eabi-gcc)
    - Win32-i386, various compilers
    - Win64-Amd64,various compilers

    Well, if I would be pedantic, then in this decade I also wrote several
    programs for Arm32 Linux, where I don't know whether uint32_t is alias
    of 'unsigned int' or 'unsigned long', few programs for AMD64 Linux,
    where I know that uint32_t is an alias of 'unsigned long' and may be one program for ARM64 Linux that is the same as AMD64 Linux.
    But all those outliers together constitute a tiny fraction of the code
    that I wrote recently.









    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Sun Jan 11 15:23:35 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)

    What exactly, assuming that conditions (a) and (b) fulfilled, should implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    Most likely nothing. The behavior is undefined, so the standard places
    no requirement on implementations either to make it work as some might
    expect or to make it fail in some way.

    Both gcc and clang will issue compile-time warnings for mismatched
    format strings. They do so only if the format string is a string
    literal (or perhaps in other cases where the format string is known at
    compile time).

    If uint32_t and unsigned long have different sizes, it still might
    happen happen to "work", depending on calling conventions. Passing a
    32-bit argument and telling printf to expect a 64-bit value clearly
    has undefined behavior, but perhaps both happen to be passed in 64-bit
    registers, for example.

    And that is sort of intimate knowledge of the ABI that I don't want to exploit, as already mentioned in my other post in this sub-thread.

    So you're unwilling to assume that passing a 32-bit argument while
    telling printf to expect a 64-bit argument. Good for you, seriously.

    But you're willing to assume that it's ok if the argument and format
    string specify different 32-bit types. I'm not.

    but it can't cause troubles with production C compiler.
    Or with any C compiler that is made in intention of being used
    rather than crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'

    Not guaranteed by the language (and not true on the implementations
    I use most often).

    Did I ever say that it is guaranteed by the language or that it is
    universal in any other way?
    Normally you have much better reading comprehension than one that you demonstrate in this discussion. I'd guess that it's because I somehow
    caused you to become angry.

    Let's not make this personal. I don't want to get into an argument
    about reading comprehension, but I'll point out that I didn't say that
    you said that it's guaranteed by the language. Not everything I write
    in a followup is a refutation of what was written in the previous article. Sometimes I'm simply adding more information.

    [...]

    I never claimed that it is good idea on targets with 'unsigned int'
    that is narrower.

    I claim that it's not a good idea on any target.

    I find it *much* easier to write portable code than to spend time
    figuring out what non-portable code will happens to work on the
    platforms I happen to care about today.

    uint32_t n = 42;
    printf("%lu\n", (unsigned long)n);

    unsigned long is guaranteed by the language to be at least 32 bits.
    The conversion is guaranteed not to lose information. The format
    matches the type of the argument. And the code will work correctly
    on any conforming hosted implementation. (It might involve an
    unnecessary 32 to 64 bit conversion, but given the overhead of
    printf, that's unlikely to be a problem -- and if it is, I can use
    the appropriate macro from <inttypes.h>.)

    And to my eyes, using "%u" with a uint32_t argument is *ugly*.

    To be fair, it is not ideal.
    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient to
    use than standard macros and are equally good at carrying programmer's intentions.

    The relative beauty of a feature that isn't available hardly seems
    relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write
    non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)

    Microsoft has strong influence in committee, but was not able to push
    it into C11, where they successfully forced hands of other members on
    few much bigger and more controversial issues.
    I don't know what it means, May be, there is bold technical reason
    behind non-standardization of these size specifiers. Or may be there is
    no reason and Microsoft simply never tried.

    If I write code that depends on assumptions about the current
    platform, it still might not work for some possibly unrelated reason.
    If I write portable code in the first place and something goes
    wrong, I have one less thing to worry about as a possible cause of
    the error.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Sun Jan 11 14:56:17 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Sun, 11 Jan 2026 04:59:47 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:
    On 2026-01-09 07:18, Michael S wrote:
    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:
    ...
    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...
    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    This:
    uint32_t n = 42;
    printf("%u\n", n);
    has undefined behavior *unless* uint32_t happens to an alias for
    unsigned int in the current implementation -- not just any 32-bit
    unsigned integer type, only unsigned int.

    If uint32_t is an alias for unsigned long (which implies that
    unsigned long is exactly 32 bits), then the call's behavior is
    undefined. (It might happen to "work".)

    What exactly, assuming that conditions (a) and (b) fulfilled, should implementation do to prevent it from working?
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    Most likely nothing. The behavior is undefined, so the standard places
    no requirement on implementations either to make it work as some might
    expect or to make it fail in some way.

    Both gcc and clang will issue compile-time warnings for mismatched
    format strings. They do so only if the format string is a string
    literal (or perhaps in other cases where the format string is known at
    compile time).

    If uint32_t and unsigned long have different sizes, it still might
    happen happen to "work", depending on calling conventions. Passing a
    32-bit argument and telling printf to expect a 64-bit value clearly
    has undefined behavior, but perhaps both happen to be passed in 64-bit
    registers, for example.

    And that is sort of intimate knowledge of the ABI that I don't want to exploit, as already mentioned in my other post in this sub-thread.

    So you're unwilling to assume that passing a 32-bit argument while
    telling printf to expect a 64-bit argument. Good for you, seriously.

    But you're willing to assume that it's ok if the argument and format
    string specify different 32-bit types. I'm not.

    but it can't cause troubles with production C compiler.
    Or with any C compiler that is made in intention of being used
    rather than crafted to prove theoretical points.
    Properties are:
    a) uint32_t aliased to 'unsigned long'

    Not guaranteed by the language (and not true on the implementations
    I use most often).

    Did I ever say that it is guaranteed by the language or that it is
    universal in any other way?
    Normally you have much better reading comprehension than one that you demonstrate in this discussion. I'd guess that it's because I somehow
    caused you to become angry.

    Let's not make this personal. I don't want to get into an argument
    about reading comprehension, but I'll point out that I didn't say that
    you said that it's guaranteed by the language. Not everything I write
    in a followup is a refutation of what was written in the previous article. Sometimes I'm simply adding more information.

    [...]

    I never claimed that it is good idea on targets with 'unsigned int'
    that is narrower.

    I claim that it's not a good idea on any target.

    I find it *much* easier to write portable code than to spend time
    figuring out what non-portable code will happens to work on the
    platforms I happen to care about today.

    uint32_t n = 42;
    printf("%lu\n", (unsigned long)n);

    unsigned long is guaranteed by the language to be at least 32 bits.
    The conversion is guaranteed not to lose information. The format
    matches the type of the argument. And the code will work correctly
    on any conforming hosted implementation. (It might involve an
    unnecessary 32 to 64 bit conversion, but given the overhead of
    printf, that's unlikely to be a problem -- and if it is, I can use
    the appropriate macro from <inttypes.h>.)

    And to my eyes, using "%u" with a uint32_t argument is *ugly*.

    To be fair, it is not ideal.
    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient to
    use than standard macros and are equally good at carrying programmer's intentions.

    The relative beauty of a feature that isn't available hardly seems
    relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write
    non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)

    Microsoft has strong influence in committee, but was not able to push
    it into C11, where they successfully forced hands of other members on
    few much bigger and more controversial issues.
    I don't know what it means, May be, there is bold technical reason
    behind non-standardization of these size specifiers. Or may be there is
    no reason and Microsoft simply never tried.

    If I write code that depends on assumptions about the current
    platform, it still might not work for some reason. If I write
    portable code in the first place and something goes wrong, I have
    one less thing to worry about as a possible cause of the error.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Sun Jan 11 22:44:30 2026
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    [...]
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    Most likely nothing.
    [...]

    Sorry about the duplicate post (server problems).
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Sun Jan 11 22:47:40 2026
    From Newsgroup: comp.lang.c

    Michael S <already5chosen@yahoo.com> writes:
    On Sun, 11 Jan 2026 11:51:43 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    [...]
    Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?

    Four out of four target for which I write C programs for living in this decade:
    - Altera Nios2 (nios2-elf-gcc)
    - Arm Cortex-M bare metal (arm-none-eabi-gcc)
    - Win32-i386, various compilers
    - Win64-Amd64,various compilers

    I find that surprising. I just tried a test program that prints
    the name of the type uint32_t is an alias for (using _Generic),
    and it's alias to unsigned int on every implementation I tried.
    (Your properties are limited to systems with 32-bit int and long.)

    For an implementation where int and long are both 32 bits, it
    wouldn't have surprised me for uint32_t to be an alias either for
    unsigned int or for unsigned long, and I wouldn't care either way
    beyond idle curiosity, but all the implementations I've tried choose
    to use unsigned int.

    Well, if I would be pedantic, then in this decade I also wrote several programs for Arm32 Linux, where I don't know whether uint32_t is alias
    of 'unsigned int' or 'unsigned long', few programs for AMD64 Linux,
    where I know that uint32_t is an alias of 'unsigned long' and may be one program for ARM64 Linux that is the same as AMD64 Linux.
    But all those outliers together constitute a tiny fraction of the code
    that I wrote recently.

    One advantage of my approach is that I don't have to know or care
    what the underlying type of uint32_t is.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 12 08:21:43 2026
    From Newsgroup: comp.lang.c

    On 11/01/2026 23:56, Keith Thompson wrote:
    Michael S <already5chosen@yahoo.com> writes:

    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient to
    use than standard macros and are equally good at carrying programmer's
    intentions.

    The relative beauty of a feature that isn't available hardly seems
    relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write
    non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)


    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 <stdint.h>
    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, and
    should also be fully defined behaviour for unsigned int and unsigned
    long if these are 32 bits wide.




    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 12 08:28:23 2026
    From Newsgroup: comp.lang.c

    On 11/01/2026 20:58, Tim Rentsch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    ...

    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...

    No, it is correct on all implementation.

    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b) (see
    below) printing variables declared as uint32_t via %u is probably UB
    according to the Standard (I don't know for sure, however it is
    probable),

    I'm sure. uint32_t is an alias for some predefined integer type.

    Very likely, but I don't think the C standard requires it. TTBOMU
    the C standard allows the possibility of an implementation where
    uint32_t is type distinct from any other nameable type, and yet
    the implementation could still be conforming.

    gcc for the AVR (or more accurately, the avrlibc library for the AVR
    port of gcc) defines the various <stdint.h> types as "int" or "unsigned
    int" with special modes giving their lengths (using a gcc-specific
    extension). I am never quite sure about the compatibility of these
    types and other identically sized integer types.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 12 08:34:02 2026
    From Newsgroup: comp.lang.c

    On 12/01/2026 07:47, Keith Thompson wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Sun, 11 Jan 2026 11:51:43 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    [...]
    Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?

    Four out of four target for which I write C programs for living in this
    decade:
    - Altera Nios2 (nios2-elf-gcc)
    - Arm Cortex-M bare metal (arm-none-eabi-gcc)
    - Win32-i386, various compilers
    - Win64-Amd64,various compilers

    I find that surprising. I just tried a test program that prints
    the name of the type uint32_t is an alias for (using _Generic),
    and it's alias to unsigned int on every implementation I tried.
    (Your properties are limited to systems with 32-bit int and long.)


    On 32-bit embedded systems, it is common for uint32_t to be unsigned
    long, even though unsigned int is the same size. It perhaps comes from
    the pretty much universal definition of uint32_t as unsigned long for
    smaller embedded systems where "int" is less than 32 bits.

    On Linux systems, unsigned int seems more common even on 32-bit systems.
    Thus 32-bit EABI ARM uses unsigned long, while 32-bit Linux ARM uses unsigned int.

    (Common, of course, does not mean guaranteed - there are no doubt
    exceptions to the general pattern.)

    For an implementation where int and long are both 32 bits, it
    wouldn't have surprised me for uint32_t to be an alias either for
    unsigned int or for unsigned long, and I wouldn't care either way
    beyond idle curiosity, but all the implementations I've tried choose
    to use unsigned int.

    Well, if I would be pedantic, then in this decade I also wrote several
    programs for Arm32 Linux, where I don't know whether uint32_t is alias
    of 'unsigned int' or 'unsigned long', few programs for AMD64 Linux,
    where I know that uint32_t is an alias of 'unsigned long' and may be one
    program for ARM64 Linux that is the same as AMD64 Linux.
    But all those outliers together constitute a tiny fraction of the code
    that I wrote recently.

    One advantage of my approach is that I don't have to know or care
    what the underlying type of uint32_t is.


    Indeed.

    (I also write non-portable code where I /do/ know the underlying type -
    so I might use "lu" directly for uint32_t. But I know the code will not
    be used on other targets, and I know I have the correct specifier for
    the target I am using.)


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 12 10:34:48 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 23:51:04 +0200
    Michael S <already5chosen@yahoo.com> wrote:

    On Sun, 11 Jan 2026 11:51:43 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 Jan 2026 22:02:03 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> wrote:

    On 2026-01-09 07:18, Michael S wrote:

    On Thu, 8 Jan 2026 19:31:13 -0500
    "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu>
    wrote:

    ...

    I'd have no problem with your approach if you hadn't falsely
    claimed that "It is correct on all platforms".

    Which I didn't.

    On 2026-01-07 19:38, Michael S wrote:
    ...

    No, it is correct on all implementation.


    The quote is taken out of context.
    The context was that on platforms that have properties (a) and (b)
    (see below) printing variables declared as uint32_t via %u is
    probably UB according to the Standard (I don't know for sure,
    however it is probable), but it can't cause troubles with
    production C compiler. Or with any C compiler that is made in
    intention of being used rather than crafted to prove theoretical
    points. Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?

    Four out of four target for which I write C programs for living in
    this decade:
    - Altera Nios2 (nios2-elf-gcc)
    - Arm Cortex-M bare metal (arm-none-eabi-gcc)
    - Win32-i386, various compilers
    - Win64-Amd64,various compilers

    Well, if I would be pedantic, then in this decade I also wrote several programs for Arm32 Linux, where I don't know whether uint32_t is alias
    of 'unsigned int' or 'unsigned long', few programs for AMD64 Linux,
    where I know that uint32_t is an alias of 'unsigned long'

    Cut&past mistake here: read " of 'unsigned int' "

    and may be
    one program for ARM64 Linux that is the same as AMD64 Linux.
    But all those outliers together constitute a tiny fraction of the code
    that I wrote recently.



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 12 10:50:10 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 15:23:35 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    To be fair, it is not ideal.
    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient
    to use than standard macros and are equally good at carrying
    programmer's intentions.

    The relative beauty of a feature that isn't available hardly seems
    relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write
    non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)


    Microsoft guarantees that __int32 is compatible with int32_t and that
    'unsigned __int32' is compatible with uint32_t. The same goes for 64-bit
    types.
    That's sufficient for safe use of format specifier "%I32u" when
    printing uint32_t variables.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 12 10:51:43 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 22:44:30 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Michael S <already5chosen@yahoo.com> writes:
    [...]
    I mean short of completely crazy things that will make maintainer
    immediately fired?

    Most likely nothing.
    [...]

    Sorry about the duplicate post (server problems).


    I had my comp.arch post triplicated for the same reason.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 12 11:06:48 2026
    From Newsgroup: comp.lang.c

    On Mon, 12 Jan 2026 08:21:43 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 11/01/2026 23:56, Keith Thompson wrote:
    Michael S <already5chosen@yahoo.com> writes:

    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient
    to use than standard macros and are equally good at carrying
    programmer's intentions.

    The relative beauty of a feature that isn't available hardly seems relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)


    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 <stdint.h> 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,
    and should also be fully defined behaviour for unsigned int and
    unsigned long if these are 32 bits wide.


    It sounds very good.

    Except that none of my four targets of major interest supports C23 at
    the moment. Esp. so at the level of standard library.

    For one of them (Nios2) in the absence of something VERY unexpected
    there never be support (gcc stopped support for Nios2 2 or 3 years ago).

    For the other three, it will take time. I can't even guess how long,
    except that I know that support versions of arm-none-eabi-gcc lags two
    years behind "hosted" x86-64 and ARM64 versions, so I can guess that it
    would take significant time to catch up.






    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Mon Jan 12 11:24:09 2026
    From Newsgroup: comp.lang.c

    On Sun, 11 Jan 2026 22:47:40 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Sun, 11 Jan 2026 11:51:43 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    Michael S <already5chosen@yahoo.com> writes:
    [...]
    Properties are:
    a) uint32_t aliased to 'unsigned long'
    b) 'unsigned int' is at least 32-bit wide.

    It seems unlikely that any implementation would make such a
    choice. Can you name one that does?

    Four out of four target for which I write C programs for living in
    this decade:
    - Altera Nios2 (nios2-elf-gcc)
    - Arm Cortex-M bare metal (arm-none-eabi-gcc)
    - Win32-i386, various compilers
    - Win64-Amd64,various compilers

    I find that surprising. I just tried a test program that prints
    the name of the type uint32_t is an alias for (using _Generic),
    and it's alias to unsigned int on every implementation I tried.
    (Your properties are limited to systems with 32-bit int and long.)

    For an implementation where int and long are both 32 bits, it
    wouldn't have surprised me for uint32_t to be an alias either for
    unsigned int or for unsigned long, and I wouldn't care either way
    beyond idle curiosity, but all the implementations I've tried choose
    to use unsigned int.


    Did you try any implementation that is not based on SysV ABI?

    Well, if I would be pedantic, then in this decade I also wrote
    several programs for Arm32 Linux, where I don't know whether
    uint32_t is alias of 'unsigned int' or 'unsigned long', few
    programs for AMD64 Linux, where I know that uint32_t is an alias of 'unsigned long' and may be one program for ARM64 Linux that is the
    same as AMD64 Linux. But all those outliers together constitute a
    tiny fraction of the code that I wrote recently.

    One advantage of my approach is that I don't have to know or care
    what the underlying type of uint32_t is.


    By 'you approach' you mean casting to 'unsigned long' and using %ld
    formatter?
    As I said in other post, ideologically I like it. The only reason I
    don't adapt that approach myself is because 'unsigned long' is long
    (many characters).
    I'd do exactly that in case of int32_t, except that in practice
    int32_t is very rare in my code and printing it rarer still.
    [O.T.]
    When I can, I try to use signed integer types in preference of unsigned
    types, but those are mostly plain 'int' and ptrdiff_t, occasionally
    int16_t, rarely 'long'. int32_t and int64_t are very rare.












    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 12 13:26:40 2026
    From Newsgroup: comp.lang.c

    On 12/01/2026 10:06, Michael S wrote:
    On Mon, 12 Jan 2026 08:21:43 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 11/01/2026 23:56, Keith Thompson wrote:
    Michael S <already5chosen@yahoo.com> writes:

    The solution that I would prefer would be universal adaption of
    Microsoft's size specifiers I32 and I64. They are not going to win
    beauty competition, but in practice they are a lot more convenient
    to use than standard macros and are equally good at carrying
    programmer's intentions.

    The relative beauty of a feature that isn't available hardly seems
    relevant.

    The ideal solution is to write correct, and preferably portable,
    code in the first place. There are often good reasons to write
    non-portable code, but I suggest that fiding the correct format
    string to be ugly is not one of them.

    (Microsoft's documentation says that "I32" prefix applies to an
    argument of type __int32 or unsigned __int32. I don't know whether
    __int32 is compatible with int, with long, or neither, and I don't
    much care. I don't know what Microsoft guarantees about printf
    with incompatible types that happen to have the same size.)


    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 <stdint.h> 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,
    and should also be fully defined behaviour for unsigned int and
    unsigned long if these are 32 bits wide.


    It sounds very good.

    Except that none of my four targets of major interest supports C23 at
    the moment. Esp. so at the level of standard library.


    gcc has supported the format, along with much of C23, since gcc 13, and
    ARM's gcc-based toolchain version 13.2 is from October 2023. (The
    current version is 15.2 from December 2025.) But I don't know about
    library support - that is a very different matter. (Compiler support
    for printf really just means checking the format specifiers match the parameters.)

    It is an unfortunate fact of developers' lives that we see fun new
    features in new language standards, but often have to wait years before
    we can play with them.

    For one of them (Nios2) in the absence of something VERY unexpected
    there never be support (gcc stopped support for Nios2 2 or 3 years ago).

    For the other three, it will take time. I can't even guess how long,
    except that I know that support versions of arm-none-eabi-gcc lags two
    years behind "hosted" x86-64 and ARM64 versions, so I can guess that it
    would take significant time to catch up.


    ARM's gcc-based toolchain builds are not nearly as far behind as they
    used to be. They have pretty much caught up to current stable gcc releases.

    <https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads>


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Jan 12 04:27:14 2026
    From Newsgroup: comp.lang.c

    David Brown <david.brown@hesbynett.no> 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 <stdint.h> 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 <stdarg.h>, 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 <inttypes.h>, 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 */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Mon Jan 12 17:57:23 2026
    From Newsgroup: comp.lang.c

    On 12/01/2026 13:27, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> 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 <stdint.h> 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 <stdarg.h>, 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 <inttypes.h>, 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".


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Jan 12 16:06:08 2026
    From Newsgroup: comp.lang.c

    David Brown <david.brown@hesbynett.no> writes:
    [...]

    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc 13,
    and ARM's gcc-based toolchain version 13.2 is from October 2023. (The current version is 15.2 from December 2025.) But I don't know about
    library support - that is a very different matter. (Compiler support
    for printf really just means checking the format specifiers match the parameters.)

    Of course printf is implemented in the library, not in the compiler.

    gcc has had format checking for %wN and %wfN since release 13, but
    that's useless in the absence of library support.

    Support in glibc was added 2023-06-19 and released in version 2.39.
    Other C library implementations may or may not support it.

    [...]
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Tue Jan 13 08:56:45 2026
    From Newsgroup: comp.lang.c

    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]

    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc 13,
    and ARM's gcc-based toolchain version 13.2 is from October 2023. (The
    current version is 15.2 from December 2025.) But I don't know about
    library support - that is a very different matter. (Compiler support
    for printf really just means checking the format specifiers match the
    parameters.)

    Of course printf is implemented in the library, not in the compiler.

    Primarily, yes. But like all standard library functions, compilers can
    have special handling in some ways. This is more obvious for functions
    like memcpy, where the compiler can often generate significantly better
    code (specially for small known sizes). As far as I know, the only optimisation gcc does on printf is turn something like printf("Hello\n")
    into puts("Hello"). Hypothetically, there is nothing to stop a compiler
    being a great deal more sophisticated than that, and doing the
    format-string interpretation directly in some way.


    gcc has had format checking for %wN and %wfN since release 13, but
    that's useless in the absence of library support.

    Yes.


    Support in glibc was added 2023-06-19 and released in version 2.39.
    Other C library implementations may or may not support it.


    glibc is not particularly relevant for non-Linux embedded systems.
    newlib (and newlib-nano) are a common choice for such systems, but I
    have no idea if it currently has support for those formats.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Tue Jan 13 00:53:36 2026
    From Newsgroup: comp.lang.c

    David Brown <david.brown@hesbynett.no> writes:
    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc 13,
    and ARM's gcc-based toolchain version 13.2 is from October 2023. (The
    current version is 15.2 from December 2025.) But I don't know about
    library support - that is a very different matter. (Compiler support
    for printf really just means checking the format specifiers match the
    parameters.)
    Of course printf is implemented in the library, not in the compiler.

    Primarily, yes. But like all standard library functions, compilers
    can have special handling in some ways. This is more obvious for
    functions like memcpy, where the compiler can often generate
    significantly better code (specially for small known sizes). As far
    as I know, the only optimisation gcc does on printf is turn something
    like printf("Hello\n") into puts("Hello"). Hypothetically, there is
    nothing to stop a compiler being a great deal more sophisticated than
    that, and doing the format-string interpretation directly in some way.

    Sure, but in practice the library support for printf is the only thing
    that matters. If your library doesn't support %wN, having the compiler recognize it doesn't help. I'm not sure why you even mentioned gcc in
    this context.

    gcc has had format checking for %wN and %wfN since release 13, but
    that's useless in the absence of library support.

    Yes.

    Support in glibc was added 2023-06-19 and released in version 2.39.
    Other C library implementations may or may not support it.

    glibc is not particularly relevant for non-Linux embedded
    systems. newlib (and newlib-nano) are a common choice for such
    systems, but I have no idea if it currently has support for those
    formats.

    Of course, that's why I mentioned other C library implementations.
    glibc happens to be the one about which I had some relevant
    information.

    The versions of musl and dietlibc that I have on my Ubuntu system
    don't support %wN. The version of newlib I have on Cygwin also
    doesn't support it. PellesC on Windows does.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Tue Jan 13 11:09:55 2026
    From Newsgroup: comp.lang.c

    On 13/01/2026 09:53, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc 13,
    and ARM's gcc-based toolchain version 13.2 is from October 2023. (The >>>> current version is 15.2 from December 2025.) But I don't know about
    library support - that is a very different matter. (Compiler support
    for printf really just means checking the format specifiers match the
    parameters.)
    Of course printf is implemented in the library, not in the compiler.

    Primarily, yes. But like all standard library functions, compilers
    can have special handling in some ways. This is more obvious for
    functions like memcpy, where the compiler can often generate
    significantly better code (specially for small known sizes). As far
    as I know, the only optimisation gcc does on printf is turn something
    like printf("Hello\n") into puts("Hello"). Hypothetically, there is
    nothing to stop a compiler being a great deal more sophisticated than
    that, and doing the format-string interpretation directly in some way.

    Sure, but in practice the library support for printf is the only thing
    that matters. If your library doesn't support %wN, having the compiler recognize it doesn't help. I'm not sure why you even mentioned gcc in
    this context.


    I had several reasons (I would want compiler checking of the format
    before using it, I know the state of support in gcc, and I had mentioned
    ARM's gcc toolchains as they are the standard choice of toolchains for embedded ARM systems). But I had not intended it to be the focus, since library support is the critical point. (newlibc, as far as I can tell,
    does not yet support it.)

    gcc has had format checking for %wN and %wfN since release 13, but
    that's useless in the absence of library support.

    Yes.

    Support in glibc was added 2023-06-19 and released in version 2.39.
    Other C library implementations may or may not support it.

    glibc is not particularly relevant for non-Linux embedded
    systems. newlib (and newlib-nano) are a common choice for such
    systems, but I have no idea if it currently has support for those
    formats.

    Of course, that's why I mentioned other C library implementations.
    glibc happens to be the one about which I had some relevant
    information.


    Fair enough.

    The versions of musl and dietlibc that I have on my Ubuntu system
    don't support %wN. The version of newlib I have on Cygwin also
    doesn't support it. PellesC on Windows does.


    musl and dietlibc are not suitable for non-Linux embedded systems
    either, but of course it is nice to see the progress of support in
    different libraries for different systems. (And newlibc doesn't support
    it yet - at least, not according to the online documentation.)

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Tue Jan 13 13:45:01 2026
    From Newsgroup: comp.lang.c

    On Tue, 13 Jan 2026 11:09:55 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/01/2026 09:53, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc
    13, and ARM's gcc-based toolchain version 13.2 is from October
    2023. (The current version is 15.2 from December 2025.) But I
    don't know about library support - that is a very different
    matter. (Compiler support for printf really just means checking
    the format specifiers match the parameters.)
    Of course printf is implemented in the library, not in the
    compiler.

    Primarily, yes. But like all standard library functions, compilers
    can have special handling in some ways. This is more obvious for
    functions like memcpy, where the compiler can often generate
    significantly better code (specially for small known sizes). As
    far as I know, the only optimisation gcc does on printf is turn
    something like printf("Hello\n") into puts("Hello").
    Hypothetically, there is nothing to stop a compiler being a great
    deal more sophisticated than that, and doing the format-string
    interpretation directly in some way.

    Sure, but in practice the library support for printf is the only
    thing that matters. If your library doesn't support %wN, having
    the compiler recognize it doesn't help. I'm not sure why you even mentioned gcc in this context.


    I had several reasons (I would want compiler checking of the format
    before using it, I know the state of support in gcc, and I had
    mentioned ARM's gcc toolchains as they are the standard choice of
    toolchains for embedded ARM systems).

    [O.T.]
    AFAIK, that's no longer the case. For last 3-4 years Cortex-M MCU
    vendors, in particular STMicro and TI, intensely push clang as a default compiler in their free IDEs.
    Today, in order to use gcc in the new embedded ARM project, developer
    has to make a conscious effort of rejecting vendor's default. Most
    likely, gcc compiler does not come as part of default installation
    package. It has to be downloaded and installed separately.
    I would guess that overwhelming majority of devs does not bother.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Tue Jan 13 14:32:45 2026
    From Newsgroup: comp.lang.c

    On 13/01/2026 12:45, Michael S wrote:
    On Tue, 13 Jan 2026 11:09:55 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/01/2026 09:53, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc
    13, and ARM's gcc-based toolchain version 13.2 is from October
    2023. (The current version is 15.2 from December 2025.) But I
    don't know about library support - that is a very different
    matter. (Compiler support for printf really just means checking
    the format specifiers match the parameters.)
    Of course printf is implemented in the library, not in the
    compiler.

    Primarily, yes. But like all standard library functions, compilers
    can have special handling in some ways. This is more obvious for
    functions like memcpy, where the compiler can often generate
    significantly better code (specially for small known sizes). As
    far as I know, the only optimisation gcc does on printf is turn
    something like printf("Hello\n") into puts("Hello").
    Hypothetically, there is nothing to stop a compiler being a great
    deal more sophisticated than that, and doing the format-string
    interpretation directly in some way.

    Sure, but in practice the library support for printf is the only
    thing that matters. If your library doesn't support %wN, having
    the compiler recognize it doesn't help. I'm not sure why you even
    mentioned gcc in this context.


    I had several reasons (I would want compiler checking of the format
    before using it, I know the state of support in gcc, and I had
    mentioned ARM's gcc toolchains as they are the standard choice of
    toolchains for embedded ARM systems).

    [O.T.]
    AFAIK, that's no longer the case. For last 3-4 years Cortex-M MCU
    vendors, in particular STMicro and TI, intensely push clang as a default compiler in their free IDEs.

    As far as I know, ST uses ARM's gcc build as their normal toolchain. I haven't looked at TI's development tools for a good while.

    But it is certainly the case that clang-based toolchains are gaining in popularity for non-Linux embedded ARM. I've been looking at them
    myself, and see advantages and disadvantages. However, I believe gcc is
    still dominated by a large margin, and ARM makes regular releases of
    complete toolchain packages (compiler, libraries, debugger, etc.).

    Today, in order to use gcc in the new embedded ARM project, developer
    has to make a conscious effort of rejecting vendor's default. Most
    likely, gcc compiler does not come as part of default installation
    package. It has to be downloaded and installed separately.
    I would guess that overwhelming majority of devs does not bother.


    My experience is that the majority of microcontroller vendors provide
    gcc toolchains as part of their default installations. They used to
    have their own gcc toolchain builds, or use third-parties like Code
    Sourcery, but these days they usually use an off-the-shelf ARM package.
    But several vendors are in a transition period where they are gradually
    moving from established Eclipse-based tools towards VS Code tools, and
    perhaps clang is either an option or default with their newer IDEs.
    Those vendors provide, support and maintain both IDEs at the moment, but sometimes detailed support for particular microcontrollers only exists
    for one of them.

    I agree that most developers will use whatever compiler comes as default
    with their vendor-supplied IDEs. Personally, I think that's fine for
    getting started, or for quick throw-away projects. For anything serious
    I prefer to have the build controlled from outside the IDE (by a
    makefile), using the toolchain I choose (typically the latest ARM gcc toolchain when the project starts, then remaining consistent throughout
    the lifetime of the project). The IDEs can still be good editors, IDEs, debuggers, etc.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Tue Jan 13 17:47:27 2026
    From Newsgroup: comp.lang.c

    On Tue, 13 Jan 2026 14:32:45 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/01/2026 12:45, Michael S wrote:
    On Tue, 13 Jan 2026 11:09:55 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/01/2026 09:53, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 13/01/2026 01:06, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    Context: %wN and %wfN printf length modifier, new in C23.

    gcc has supported the format, along with much of C23, since gcc
    13, and ARM's gcc-based toolchain version 13.2 is from October
    2023. (The current version is 15.2 from December 2025.) But I
    don't know about library support - that is a very different
    matter. (Compiler support for printf really just means
    checking the format specifiers match the parameters.)
    Of course printf is implemented in the library, not in the
    compiler.

    Primarily, yes. But like all standard library functions,
    compilers can have special handling in some ways. This is more
    obvious for functions like memcpy, where the compiler can often
    generate significantly better code (specially for small known
    sizes). As far as I know, the only optimisation gcc does on
    printf is turn something like printf("Hello\n") into
    puts("Hello"). Hypothetically, there is nothing to stop a
    compiler being a great deal more sophisticated than that, and
    doing the format-string interpretation directly in some way.

    Sure, but in practice the library support for printf is the only
    thing that matters. If your library doesn't support %wN, having
    the compiler recognize it doesn't help. I'm not sure why you even
    mentioned gcc in this context.


    I had several reasons (I would want compiler checking of the format
    before using it, I know the state of support in gcc, and I had
    mentioned ARM's gcc toolchains as they are the standard choice of
    toolchains for embedded ARM systems).

    [O.T.]
    AFAIK, that's no longer the case. For last 3-4 years Cortex-M MCU
    vendors, in particular STMicro and TI, intensely push clang as a
    default compiler in their free IDEs.

    As far as I know, ST uses ARM's gcc build as their normal toolchain.
    I haven't looked at TI's development tools for a good while.


    You are right.
    I downloaded the latest version of ST CubeIDE (2.0.0).
    It claims to support STARM-Clang (not that I figured out how exactly),
    but gcc is a default toolchain, same like in 1.x
    I played with it for a few minutes then uninstalled as fast as I can.

    But it is certainly the case that clang-based toolchains are gaining
    in popularity for non-Linux embedded ARM. I've been looking at them
    myself, and see advantages and disadvantages. However, I believe gcc
    is still dominated by a large margin, and ARM makes regular releases
    of complete toolchain packages (compiler, libraries, debugger, etc.).

    Today, in order to use gcc in the new embedded ARM project,
    developer has to make a conscious effort of rejecting vendor's
    default. Most likely, gcc compiler does not come as part of default installation package. It has to be downloaded and installed
    separately. I would guess that overwhelming majority of devs does
    not bother.

    My experience is that the majority of microcontroller vendors provide
    gcc toolchains as part of their default installations. They used to
    have their own gcc toolchain builds, or use third-parties like Code Sourcery, but these days they usually use an off-the-shelf ARM
    package. But several vendors are in a transition period where they
    are gradually moving from established Eclipse-based tools towards VS
    Code tools, and perhaps clang is either an option or default with
    their newer IDEs. Those vendors provide, support and maintain both
    IDEs at the moment, but sometimes detailed support for particular microcontrollers only exists for one of them.

    I agree that most developers will use whatever compiler comes as
    default with their vendor-supplied IDEs. Personally, I think that's
    fine for getting started, or for quick throw-away projects. For
    anything serious I prefer to have the build controlled from outside
    the IDE (by a makefile), using the toolchain I choose (typically the
    latest ARM gcc toolchain when the project starts, then remaining
    consistent throughout the lifetime of the project). The IDEs can
    still be good editors, IDEs, debuggers, etc.


    For me Eclipse-based IDE is slower and harder to use than command line
    in any situation.
    Although I am ready to admit that TI did better job than most of
    turning Eclipse into something almost palatable.
    Still, even Eclipse in form of TI's CCS is an obstacle for me rather
    than help.

    --- Synchronet 3.21a-Linux NewsLink 1.2