home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 242,909 of 243,242   
   David Brown to Michael S   
   Re: printf and time_t (1/2)   
   08 Jan 26 11:35:27   
   
   From: david.brown@hesbynett.no   
      
   On 08/01/2026 00:26, Michael S wrote:   
   > On Wed, 07 Jan 2026 13:28:45 -0800   
   > Keith Thompson  wrote:   
   >   
   >> scott@slp53.sl.home (Scott Lurndal) writes:   
   >>> Keith Thompson  writes:   
   >>>> Michael S  writes:   
   >>>>> On Tue, 6 Jan 2026 10:31:41 -0500   
   >>>>> James Kuyper  wrote:   
   >>>>>> On 2026-01-06 04:29, Michael S wrote:   
   >>>>>>> On Tue, 6 Jan 2026 00:27:04 -0000 (UTC)   
   >>>>>>> Lawrence D’Oliveiro  wrote:   
   >>>>>> ...   
   >>>>>>>> Section 7.8 of the C spec defines macros you can use so you   
   >>>>>>>> don’t 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 .  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.   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca