Path: csiph.com!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: int a = a Date: Thu, 20 Mar 2025 12:46:16 -0700 Organization: None to speak of Lines: 103 Message-ID: <87msdfscxj.fsf@nosuchdomain.example.com> References: <87sen8u5d5.fsf@nosuchdomain.example.com> <86zfhgni2a.fsf@linuxsc.com> <87cyect356.fsf@nosuchdomain.example.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Thu, 20 Mar 2025 20:46:17 +0100 (CET) Injection-Info: dont-email.me; posting-host="2f20008cbcfa55ae60494be276e0bfaa"; logging-data="4043012"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19EYLiOTgPR6RDYOlkjfMVR" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:vHqY5eNqefqyTX9PWIcPCBuWino= sha1:GSkY+CvJLldBDjqM66CzsPVsvtU= Xref: csiph.com comp.lang.c:391438 David Brown writes: > On 20/03/2025 11:20, Keith Thompson wrote: >> Tim Rentsch writes: >>> Keith Thompson writes: >>>> The "could have been declared with the register storage class" >>>> seems quite odd. And in fact it is quite odd. >>> >>> I don't have the same reaction. The point of this phrase is that >>> undefined behavior occurs only for variables that don't have >>> their address taken. The phrase used describes that nicely. >>> Any questions related to "registerness" can be ignored, because >>> 'register' in C really has nothing to do with hardware registers, >>> despite the name. >> DR 338 is explicitly motivated by an IA-64 feature that applies only >> to >> CPU registers. An object whose address is taken can't be stored (only) >> in a register, so it can't have a NaT representation. >> The phrase used is "could have been declared with register storage >> class >> (never had its address taken)". Surely "never had its address taken" >> would have been clear enough if CPU registers weren't a big part of the >> motivation. > > I too think the phrasing is a bit odd. > > Just because a variable's address is taken, does not mean it cannot be > put in a cpu register by the compiler. If the variable is not > accessed in a way that actually requires putting it in memory, then > the compiler can put it in a cpu register (or otherwise optimise it). > So simply taking the address of a variable on IA-64 does not mean it > cannot be in a register, and thus does not necessarily mean it cannot > be NaT. Taking the address of a variable means the variable cannot be > declared "register", but it does not mean it cannot be /in/ a > register. Sure, any variable that's stored in memory can be mirrored by holding its value in a register. int n = 42; // Assume n is assigned a memory address printf("n+1=%d n+2=%d\n", n+1, n+2); A compiler could plausibly store the value of n in a register before computing n+1, and then reuse the register value to compute n+2. My understanding is that IA-64 NaT (Not a Thing) representations exist only for registers, and the NaT bit should be cleared when a value is stored in the register. The odd wording in the standard allows an IA-64 C compiler to take advantage of NaT representations for their intended purpose. It might impose some minor constraints on what machine code can be generated, but *most* of the cases where a NaT could be accessed are undefined behavior in C. > It seems very strange to me that this is UB: > > int foo1(void) { > int x; > > return x; > } > > while this is not : > > int foo2(void) { > int x; > > int * p = &x; > > return x; > } > > (Unfortunately, godbolt.org doesn't seem to have a gcc IA-64 compiler > in its list.) > > It strikes me that it would have been far simpler for the standard > simply to say that using the value of an uninitialised and unassigned > variable is undefined behaviour. In C90, it was. C99 changed that, making the behavior defined if the representation is not a trap representation. For C99, a conforming IA-64 C compiler would have had to go out of its way to avoid accessing NaT representations. For example, if you wrote { int n; n; } the most straightforward IA-64 code would store n in a register and not initialize it, resulting in a trap when the register is read. A compiler might have to generate code to store an arbitrary value in the register to void the trap. I'm undecided on whether reading the value of an uninitialized automatic object *should* be undefined behavior, but given that it isn't, the C11 committee made the smallest possible change to cater to IA-64 semantics. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */