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.std.c Subject: Re: 7.17.7.5 The atomic_fetch and modify generic functions and "address types" Date: Wed, 01 Jan 2025 21:32:39 -0800 Organization: None to speak of Lines: 127 Message-ID: <87a5c9u6fc.fsf@nosuchdomain.example.com> References: <86r05lalbd.fsf@linuxsc.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Date: Thu, 02 Jan 2025 06:32:45 +0100 (CET) Injection-Info: dont-email.me; posting-host="a6ca1a2a8a1a56868adae0581a86a375"; logging-data="3375949"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/my49J1s1yYd5e4xSFNX1k" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:CURIepOhF+BXSab6vXTdBkP1yWs= sha1:Fn3fKWnJh+Z3urc+G6dwVjlaQ+Y= Xref: csiph.com comp.std.c:6665 Tim Rentsch writes: > Andrey Tarasevich writes: >> 7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5) >> >>> 1 The following operations perform arithmetic and bitwise >>> computations. All of these operations are applicable to an object of >>> any atomic integer type. None of these operations is applicable to >>> atomic_bool. >> >> If I understand it correctly, this wording is intended to restrict >> these operations to integers types only. I.e. they shall not be >> applied to atomic pointer types. Is that correct? > > I believe the intent is that the atomic_fetch_key() family of > functions may be called with either atomic integer types or atomic > pointer types (with the possible exception of atomic boolean types). > > If the committee had meant to rule out atomic pointer types, the > standard could have given an explicit statement to that effect, like > what was done for atomic boolean types. The standard does not > include any explicit statement ruling out the use of atomic pointer > types; if anything atomic pointer types are implicitly included by > the parameter type name A, which is described in 7.17.1 paragraph 5 > (paragraph 6 in some later versions of the standard). > > Similarly, if the committee had meant to rule out atomic pointer > types, there is no reason for the last sentence in paragraph 3, > talking about what behaviors are allowed when address types are > used. Presumably the phrase "address types" is meant to be the same > as "pointer types" (see also below), which seems like the only > plausible interpretation. I think the only plausible explanation is that "address types" refers to atomic_address, a type that was specified in N1547 but dropped some time before N1570 (though I'm not sure why it's plural.) > There is no reason to think the inclusion of the last sentence of > paragraph 3 is an oversight. This sentence has survived unchanged > for more than 14 years, going back to at least 2010. But other > parts of section 7.17 were changed significantly during that time; > hence it seems unlikely that such an important incongruity was > missed over all of that time. > > Why then does the standard take the trouble to say that these > operations are applicable to atomic integer types? I think the > confusion comes from reading "applicable" as "allowed". A more > consistent reading is for "applicable" to mean "well-defined". I think that's a bit of a stretch. If that's the intent, it should just say "well-defined" (or just "defined"). The standard should say what it means by "applicable", or it should be worded more clearly. Given the current wording, I suppose applying atomic_fetch_add() to atomic_bool would have undefined behavior. IMHO making it a constraint violation would have made more sense (but constraints appear only in section 6 of the standard). > All > of the atomic_fetch_key() family of functions are well-defined for > all inputs of atomic integer type, even going so far as to stipulate > two's complement with wraparound for signed types (and this at a > time when the C standard did not require two's complement for signed > integer types generally). Atomic pointer types do not have this > property of producing well-defined results. Indeed, there is a > limited degree of undefined behavior that may result. In that sense > the operations of atomic_fetch_key() are not fully applicable to > atomic pointer types. But not applicable does not mean disallowed. >> Later 7.17.7.5 also says >> >>> 3 For address types, the result may be an undefined address, but the >>> operations otherwise have no undefined behavior. >> >> However, I was unable to find any mention of "address types" anywhere >> in the standard. What types are "address types"? > > The phrase "address types" is a holdover from earlier drafts of the > C standard. It's instructive to compare N1547, a draft from > December 2010, to N1570, a draft from April 2011. The phrase > "address types" is used in several places, including to describe a > type name "atomic_address" (a struct type). I won't go through all > of the differences, which are fairly widespread. But looking them > over is I think convincing that pointer types were left in > deliberately. N1574 specifies a type "atomic_address", which didn't survive into C11 (good catch, BTW). N1574 7.17.7.5 says that the atomic_fetch_* functions (only addition and subtraction, a distinction that doesn't appear in N1570) are applicable to atomic_address, not to atomic pointer types in general. I see no indication that the functions are meant to be "applicable" to atomic pointer types. The phrase "address types" should have been changed to "pointer types", *if* that's what was intended. Certainly atomic pointer types are valid. The question is which of the atomic_fetch_* and atomic_modify_* function can be (meaningfully) applied to them. If the _add and _sub functions are applied to an atomic pointer type, is the unit of addition or subtraction one byte or one element? N1547 explicitly says that it's one byte for atomic_address. Addition and subtraction by elements is the only thing that makes sense for atomic pointer types, but the standard doesn't specify it. > A point that needs clarifying is whether bitwise operations are > allowed for atomic pointer type. The bitwise operations are allowed > by gcc, and disallowed by clang. I think an argument can be made > either way. Personally I think allowing bitwise operations is more > compelling than disallowing them, but I have to acknowledge the > possibility that the intent was place them off limits (meaning, > requiring a diagnostic). That said, I don't see any explicit text > in the standard that forces that conclusion. There's nothing in the standard to suggest that _add and _sub should be valid for atomic pointer types but _or, _xor, and _and should not. But IMHO there should be. Addition and subtraction of (atomic) pointer types could be well defined; bitwise operations are not. The simplest explanation is that this is a flaw in the standard. It happens. [...] -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */