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,961 of 243,242   
   Keith Thompson to Michael S   
   Re: printf and time_t (1/2)   
   11 Jan 26 14:56:17   
   
   From: Keith.S.Thompson+u@gmail.com   
      
   Michael S  writes:   
   > On Sun, 11 Jan 2026 04:59:47 -0800   
   > Keith Thompson  wrote:   
   >> Michael S  writes:   
   >> > On Sat, 10 Jan 2026 22:02:03 -0500   
   >> > "James Russell Kuyper Jr."  wrote:   
   >> >> On 2026-01-09 07:18, Michael S wrote:   
   >> >> > On Thu, 8 Jan 2026 19:31:13 -0500   
   >> >> > "James Russell Kuyper Jr."    
   >> >> > 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 .)   
   >>   
   >> 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 */   
      
   --- 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