Path: csiph.com!weretis.net!feeder9.news.weretis.net!news.misty.com!news.iecc.com!.POSTED.news.iecc.com!nerds-end From: Keith Thompson Newsgroups: comp.compilers,comp.lang.c Subject: Re: Undefined behaviour in C23 Date: Sat, 23 Aug 2025 15:58:46 -0700 Organization: Compilers Central Sender: johnl%iecc.com Approved: comp.compilers@iecc.com Message-ID: <25-08-014@comp.compilers> References: <25-08-002@comp.compilers> <25-08-003@comp.compilers> <25-08-005@comp.compilers> <25-08-007@comp.compilers> <25-08-008@comp.compilers> <25-08-011@comp.compilers> <25-08-012@comp.compilers> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="95605"; mail-complaints-to="abuse@iecc.com" Keywords: C, standards Posted-Date: 23 Aug 2025 20:21:26 EDT X-submission-address: compilers@iecc.com X-moderator-address: compilers-request@iecc.com X-FAQ-and-archives: http://compilers.iecc.com Xref: csiph.com comp.compilers:3688 comp.lang.c:394222 This discussion started in comp.compilers (which is moderated). I've cross-posted to comp.lang.c and set followups there. I've snipped some context. David Brown writes: > On 23/08/2025 00:11, Keith Thompson wrote: >> comp.lang.c would probably be a better place for this discussion, >> but cross-posting between moderated and unmoderated newsgroups is >> likely to cause problems. > > Yes - but some comments have also wandered slightly from being just > applicable to C. Still, it is not really a compiler discussion. > > [FYI, cross-posting to comp.compilers and other groups works because > your moderator's scripts know how to handle it. -John] > >> David Brown writes: >>> On 21/08/2025 21:53, Keith Thompson wrote: >> [...] >>> If you declare and call a function "foo" that is written in fully >>> portable C code, but not part of the current translation unit being >>> compiled (perhaps it has been separately compiled or included in a >>> library), then it would be UB by the section 4 definition (since the C >>> standards don't say anything about what "foo" does, nor does your code). >> >> If the translation unit that defined "foo" is part of your program, then >> your code *does* define its behavior. Linking multiple translation >> units into a program is specified by the C standard; it's translation >> phase 8. > > No. Yes. > The C standard does not define how this linking or combing is done - it > only covers certain specific aspects of the linking that relate directly > to C. The behaviour of the function "foo" here is not defined in the C > standards, and if the source code is not available when translating a > different translation unit, the behaviour of "foo" is undefined. It doesn't matter how linking is done, only that it follows the semantics of C. The function "foo" is *part of the program*. The fact that it's in a different translation unit doesn't affect its semantics. A C program can be made up of multiple translation units. The behavior of a call to foo() is the same whether it's defined in the same translation unit or not. Linking, translation phase 8, ensures that that's the case. [...] > The C code being translated has code to call the function - the call is > defined (assuming declarations and definitions are consistent), but the > effect of the call is not defined - it is therefore UB. Again, the effect of the call is specified by the definition of foo, which is *part of your program*. [...] >>> Add to that, the C standard has a specific term for features that are >>> non-portable but not undefined behaviour - "implementation-defined >>> behaviour". Code that relies on "int" being 32-bit is not portable, but >>> it is not UB when compiled on implementations for which "int" /is/ 32-bit. >> >> That's not what "implementation-defined behavior" means in C. >> Cases of implementation-defined behavior are explicitly called out in >> the standard, and an implementation must document how it treats each >> instance of implementation-defined behavior. Each implementation >> must document the range of int. There is no such requirement for >> the behavior of "foo" defined in some non-standard header. > > Yes, exactly - implementation-defined behaviours are things that are not > portable, but are not undefined behaviour, because they must be defined > by the implementation. (The C standard usually also gives some specific > options or minimum requirements for those definitions.) You're ignoring two critical requirements for behavior to be implementation-defined: it has to be specified by the standard as implementation-defined (unlike undefined behavior, there is no implicit implementation-defined behavior), and the implementation's choice of behavior must be documented. Neither of these applies to a function defined outside your program (unless it's part of the C standard library). [...] > Section 4 says precisely that behaviour that is not defined by the C > standard, is "undefined behaviour" in exactly the same way as things > that are explicitly labelled "undefined behaviour" in the standard. Yes. > And that, I think, is the root of the problem - the C standard is on the > one hand trying to classify, define and describe things as "undefined > behaviour" as a technical term in the C standard, while on the other > hand it is also trying to say these are things that have no definition > or descriptions of their behaviours. I see no problem. For any construct whose behavior is undefined, the standard says that it provides no definition of its behavior. This is equally true whether the standard explicitly says the behavior is undefined or it just omits any definition of the behavior. >> It is behavior that >> is not defined *by the C standard*. If I write printf("goodbye\n") >> when I meant to write printf("hello\n"), that's incorrect behavior, >> but it's not undefined behavior. >> > > I agree that it is not C undefined behaviour, yes. [...] Excellent. It's entirely possible for a construct that has undefined behavior according to the C standard to have its behavior defined elsewhere (e.g., by POSIX). When discussing C, using the phrase "undefined behavior" with a meaning other than the C standard definition will only cause confusion. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */