Path: csiph.com!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c++ Subject: Re: is "x *= ++f * ++f" a valid statement ? Date: Mon, 22 Jul 2024 20:40:37 -0700 Organization: None to speak of Lines: 55 Message-ID: <877cdchj2i.fsf@nosuchdomain.example.com> References: <96127c8d8d204b7c3230828101bc2b6e@www.novabbs.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Date: Tue, 23 Jul 2024 05:40:42 +0200 (CEST) Injection-Info: dont-email.me; posting-host="8f89c54951c1f9a4cd0a54f8e4f1e5f6"; logging-data="1115057"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/8nZCzwuwgGSIHnqeVurh4" User-Agent: Gnus/5.13 (Gnus v5.13) Cancel-Lock: sha1:YGf03pF3XbowYn3n5haim2HSMHo= sha1:fTozJEAgYZrAz+vC5kYWv+TCBxU= Xref: csiph.com comp.lang.c++:119722 James Kuyper writes: > On 7/22/24 13:51, testuseri2p wrote: >> I'd say in simple words, if you alter a variable multiple times in one >> statement, you get UB. > > The correct (and admittedly more complicated) statement of the relevant > rule is: > "If a side effect on a memory location (6.7.1) is unsequenced relative > to either another side effect on the same memory location or a value > computation using the value of any object in the same memory location, > and they are not potentially concurrent (6.9.2), the behavior is undefined." > > The biggest difference between the exact rule and what you said is that > two different updates to a variable may occur in the same statement, so > long as they are sequenced relative to each other. Sub-expressions of an > expression are sequenced before evaluation of the expression itself. In > general, the sub-expressions of a expression are unsequenced, but there > several exceptions: ||, &&, ?:, the comma operator. "Sub-expressions of an expression are sequenced before evaluation of the expression itself." isn't quite correct. What the C++ standard says is that "The value computations of the operands of an operator are sequenced before the value computation of the result of the operator." In `++f * ++f`, the values yielded by the two ++f subexpressions are determined before the "*" operator can be evaluated, but the side effects of incrementing f (twice) can happen any time before the end of the evaluation of the full expression. The full expression is `x *= ++f * ++f`. There are three side effects, modifications to x, f, and f, and they can happen in any order. (It's because the two modifications of f are unsequenced that the behavior is undefined. `x *= ++f * ++g` would be well defined, as long as there f and g are initialized and aren't any hidden games with any of x, f, and g being references to the same object. And the side effects on f and g could happen before or after the multiplication and assignment are evaluated. > A minor detail is that a variable must be declared, whereas memory > locations can, for instance, be part of allocated memory for which no > declaration exists - it is still undefined behavior to write code that > applies unsequence side-effects to such memory locations. Digression: I'm not even sure what "variable" means in C++. The standard defines the term, but not in a way that really tells us what it means. "A *variable* is introduced by the declaration of a reference other than a non-static data member or of an object. The variable’s name, if any, denotes the reference or object." -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com void Void(void) { Void(); } /* The recursive call of the void */