3

Consider the following code:

int main(){
  int i = 0;
  int a = ++i + ++i;
}

I can't find any information that says that the operands of + are unsequenced. So according to the standard, the sequence of operands of binary + are indeterminately sequenced.

[intro,excution]/15

Given any two evaluations A and B, if A is sequenced before B (or, equivalently, B is sequenced after A), then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap.  — end note ]

Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.[ Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first.  — end note ]

The quote means that the evaluation of A can occur before B or the evaluation of B can occur before A. And the execution of unsequenced evaluations can overlap, whereas indeterminately sequenced evaluations cannot overlap, which are different.

We know the modification of i always occurs before value computation of i due to prefix ++.

Then according to the rules:

Evaluation of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects

If a side effect on a memory location 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, the behavior is undefined

So regardless of whether the evaluation of A is before B or the converse, there are no side effects related to corresponding value computation or side effect for ++i + ++i;. Because indeterminately sequenced evaluations cannot overlap, one of the two evaluation must be completely executed before the other. The evaluation includes both value computation and side effect. Therefore, one increment to i is evaluated before the other.

Unsequenced evaluations, however, follow different rules, so the confusion will be resolved if the evaluations of operands of binary + are unsequenced rather than indeterminately sequenced. If I missed something in the standard in the analysis above, please correct me.

Update

I found the following sentence, which seems to suggest that the evaluations are unsequenced:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

However, I don't know how to understand the sentence correctly. I came up with two interpretations:

For an operator A, the evaluations of the operands of A are unsequenced with each other; for an expression B, the evaluations of the subexpressions of B are unsequenced with each other.

and

Take evaluations of operands of individual operators as A. Take evaluations of subexpressions of individual expressions as B. A is unsequenced with B.

Which interpretation is correct?

L. F.
  • 19,445
  • 8
  • 48
  • 82
xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • 3
    https://en.wikipedia.org/wiki/KISS_principlev - Makes life easier – Ed Heal Apr 17 '20 at 04:55
  • 1
    @EdHeal yeah,I just want to understand these rules based on the standard,I think nobody could write code like this. – xmh0511 Apr 17 '20 at 05:01
  • 2
    could -> should would be better. As to the standard - it is rather vague on this matter. Just write readable code that is simple to understand – Ed Heal Apr 17 '20 at 05:04
  • @EdHeal thanks for your suggestion."it is rather vague on this matter",Do you mean that there is really no description about sequence for additive operator and it's unclear in the standard? – xmh0511 Apr 17 '20 at 05:08
  • I have not read the standard for years. I just know it is wrong and why worry over it. Just write readable and understandable code – Ed Heal Apr 17 '20 at 05:10
  • @EdHeal ok.I just want to know whether I understand what the standard said correctly – xmh0511 Apr 17 '20 at 05:12
  • I think your example is comparable to f(++i, ++i); https://en.cppreference.com/w/cpp/language/eval_order says it is 'undefined behavior until C++17, unspecified after C++17'. In your original question UB is undefined behaviour? Then no, since C++17 it is unspecified now. Much better :-) [The difference is whether the standard recognizes this case and just leaves it to the compiler implementors or whether the case is just a gap in the standard rules]. – Sebastian Apr 17 '20 at 05:13
  • @Sebastian may be.So could you give an answers about these? – xmh0511 Apr 17 '20 at 05:19
  • +1 on @EdHeal comment. (Ed please fix wiki link.) Unless you're an academic or into trivia, if you can't find a clear explanation of the behaviour for a certain expression or statement in the spec, just avoid it. – rtx13 Apr 17 '20 at 05:21
  • @rtx13 may be I want to study the standard :-) – xmh0511 Apr 17 '20 at 05:23
  • @Sebastian the only things I have found in the standard is that "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced",I don't know how to understand the sentence?Taken evaluations of operands of individual operators as A and evalution of subexpressions of individual expressions as B,Does the sentence means that A and B are unsequenced.or the evalution of one operand of individual operator is unsequenced the evalution of the other operand of that individual operator? – xmh0511 Apr 17 '20 at 05:29
  • I can't tell, is your question materially different from [this one](https://stackoverflow.com/q/949433/10957435). –  Apr 17 '20 at 05:58
  • @Chipster that question is under c,my question is under c++17. – xmh0511 Apr 17 '20 at 06:09
  • https://en.wikipedia.org/wiki/KISS_principle is the link – Ed Heal Apr 17 '20 at 08:42
  • 1
    For your update, the correct reading is "Take the set of all operands, union the set of all subexpressions to form a combined set. Every element of that set is unsequenced wrt every other element (unless another rule steps in and guarantees sequencing of those two elements)." Since an operand *is* a subexpression, your attempt to draw two alternatives requires a dichotomy that just doesn't exist. – Ben Voigt Apr 17 '20 at 15:32
  • @BenVoigt thanks,I hope you could post answers for these questions,It would be wonderful. – xmh0511 Apr 17 '20 at 15:40
  • @jackX: Multiple questions in one post is just not how Stack Overflow works. Answers are only valid if they try to address the main question. (And you cannot change the main question in an edit, you can only add clarifying information) – Ben Voigt Apr 17 '20 at 15:43
  • @BenVoigt yes,however I think you solved my questions precisly,and that is what i want,but these answers are dispersed.It's no convient for person who have the same question to find these – xmh0511 Apr 17 '20 at 15:48
  • @BenVoigt or may be I can post a new question about how to understand keyword such as "unsequenced","indetermined sequences" etc. tomorrow morning.By the way,I think the arguments of function call are inderminted sequenced... – xmh0511 Apr 17 '20 at 15:54

2 Answers2

3

The standard text seems1 to imply that the behavior is undefined.

  • in <a>+<b> the evaluations of <a> and <b> are unsequenced2,3
  • the two parts have side effect that affect the same memory location

(1) This part is in my opinion unambiguous and clear, but I'm not sure there are not other parts that are saying the opposite or that some higher level concept (e.g. what is the execution of a program) is not logically broken because of contradicting rules. Given the complexity of C++ I would actually be quite surprised of no errors being present.

(2) In case of an overloaded operator+ they would be indeterminately sequenced (as the rules are the same as for a function call, thus NOT undefined behavior: 8.5.1.2[5] of N4713 says "The postfix-expression is sequenced before each expression in the expression-list and any default argument. The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter") but for native ints this does not apply and the behavior is undefined.

(3) The text says "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced". Of course for unary operators the question is irrelevant (there is no ordering to talk about) and for the ternary ?: operator there are special sequencing rules. The part about "subexpressions" is to cover cases like a[++i][++i] where a is for example a char **: in this case the two identical sub-expressions ++i are unsequenced and with side effects modifying the same memory location and thus undefined behavior. I think the paragraph is actually more complex than necessary because operands of an operator are also subexpressions of an expression thus the last part was sufficient.

6502
  • 112,025
  • 15
  • 165
  • 265
  • I can't find any wording in standard that say "in + the evaluations of and are unsequenced(**)" – xmh0511 Apr 17 '20 at 07:43
  • 2
    @jackX: exactly... "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced." – 6502 Apr 17 '20 at 07:47
  • thanks,however please look the **UPDATE** part in my questions,they are my understanding about this sentence,I don't know which understanding is correctly. – xmh0511 Apr 17 '20 at 07:49
  • @jackX: the cases are: 1) A sequenced before B; 2) B sequenced before A; 3) A indeterminately sequenced in respect to B; 4) unsequenced. In case 4 if the two parts have subexpressions that as side effect change the same memory location the behavior is undefined. Case 4 is also the default case unless specific rules are present. – 6502 Apr 17 '20 at 07:58
  • Your meaning is that what the sentence mean is: take "evalution of one operand of individual operator" as `A`, take "evalution of the other operand of the same individual operator" as `B`,and the sentence says `A` and `B` are unsequenced,Right? rather than take "evaluations of operands of individual operators" as `A`,take "evaluations of subexpressions of individual expressions" as B,A and B are sequenced. – xmh0511 Apr 17 '20 at 08:14
  • @jackX: the current standard is clear that to compute `a+b` the actual sum is sequenced after the value computation of `a` and `b`. Something that in my opinion is illogical is that the value of `++i` depends on the side effect (the value of `++i` is a reference, in other words an address and doesn't change because of increment) but that's irrelevant. The problem are two unsequenced increments of the same memory location. – 6502 Apr 17 '20 at 08:19
  • Firstly " the current standard is clear that to compute a+b the actual sum is sequenced after the value computation of a and b" where's wording in standard,please cite the link here.Secondly,the side effect of `++i` is sequenced before value compution of expression `++i`,due to prefix `++` – xmh0511 Apr 17 '20 at 08:24
  • @jackX: That `+` in `a+b` is sequenced after `a` and `b` is stated as "The value computations of the operands of an operator are sequenced before the value computation of the result of the operator". What I find strange about discussing the value of `++i` is that the result is an lvalue, thus an address, thus independent on if the increment has been done or not. I think however the rule was needed because `f(++i)` where the function was taking an integer parameter would have had questionable semantic otherwise. – 6502 Apr 17 '20 at 08:49
  • I don't think so.Because the evalution of expression only concerned about value computation and side effect.exclude value category of expression.I think the question itsleft is the standard doesn't say that the evalution of operand of binary `+` is unsequenced.`function` is another question – xmh0511 Apr 17 '20 at 09:02
  • @jackX: English is not my native language so may be you're seeing a nuance I don't understand. The standard doesn't say anything special about operator `+` and thus the general rule that says that operands of an operator are unsequenced applies and this implies undefined behavior (for example binary operator `||` is different). The text about subexpressions is for example to cover `x[++i][++i]` where the two subexpressions `++i` are unsequenced if `x` is for example a `char **`. – 6502 Apr 17 '20 at 10:21
  • yes,I just agree with you that the standard doesn't say anything about order of evalution of operands of operator `+`,then,please look at this:"Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.",In my point view,It means that if the standard does not say whether the sequence is before or after,then it's indetermined sequence,just as the definiton of `ndetermined sequence`.So reback to order of evalution of operands.as you said,the standard say nothing,hence I think it's determined. – xmh0511 Apr 17 '20 at 11:13
  • If not that,I appreciate for you to find out the quotes that say the order of evalution of operand of binary `+` are **unsequenced**,thanks – xmh0511 Apr 17 '20 at 11:15
  • 1
    @jackX: the term "indeterminately sequenced" has a very strict meaning and is very different from "unsequenced": it meas that they are sequenced but it's unspecified how (and the sequence is not even necessarily the same in case of multiple evaluation of the same expression). When the "indeterminately sequenced" guarantee applies is however specified (for example arguments in a function call ... see 8.5.1.2[5] in N4713); the default when nothing is said is however "unsequenced", and this is stated clearly. – 6502 Apr 17 '20 at 11:37
  • @ I seem to have understood what you are saying.such as a function call which has two arguments,namely A and B,indetermined sequence means either A before B or B before A,but the standard does not specified which one.The unsequenced means the order as if it's random.If the standard does not say the order of evalution of operand,then the default behaviour is that they are unsequenced,Right? – xmh0511 Apr 17 '20 at 12:41
  • Your point (2) I believe is wrong. Even if `operator+` is a function call, evaluation of its arguments is unsequenced. If both prefix and postfix variants of `operator++` were function calls, on the other hand, the two calls would not be concurrent, thus indeterminately sequenced. – Ben Voigt Apr 17 '20 at 15:28
  • @6502. Thanks for your answers,I have modified `UPDATE` part ,so your understanding about the sentence "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced" should be `#1 Meaning` ,Right? – xmh0511 Apr 17 '20 at 15:30
  • 1
    @jackX: "unsequenced" doesn't mean the order is random, it means that the parts of each evaluation can even be interleaved together. "indeterminately sequenced" means there's no overlap between the evaluations, but it isn't specified which happens first. – Ben Voigt Apr 17 '20 at 15:30
  • @BenVoigt thanks,I have some confusions about the sentence in my question `UPDATE` part,and I have listed some my understanding about this sentence,I don't know which is right,so,could you help me understand that sentence? – xmh0511 Apr 17 '20 at 15:33
  • @BenVoigt: I've added to point 2 the citation I think is relevant, why do you think it doesn't apply? – 6502 Apr 17 '20 at 18:06
  • @6502: It does apply, it's just that I saw a rationale from Bjarne describing it as "unconstrained", and "indeterminately sequenced" does constrain them to not be interleaved. – Ben Voigt Apr 17 '20 at 18:28
  • @6502 Is (2) also true for prefix operators? Your quote is about postfix. – Sebastian Apr 18 '20 at 04:35
  • @Sebastian: that quote is about function calls, not unary/binary operators. A function call in c++ is a "postfix expression" (formally defined in N4713:8.5.1) followed by an open parenthesis, an optional "initializer-list" and a closed parenthesis; all quoted terms in this phrase are syntax elements formally defined in the standard. In C++ you can write a function call for example as `x[3](1,2,3)` where `x[3]` is the "postfix expression" that the quoted text is talking about. My point 2 is just to say that In case of overloaded operators the semantic is the one of function call. – 6502 Apr 18 '20 at 07:52
2

Let me give a answers to make answers of the question more clealy. Firstly,consider the following sentence

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

the sentence can be splited two

1.Except where noted,evaluations of operands of individual operators are unsequenced.
2.Except where noted,evaluations of subexpressions of individual expressions are unsequenced.

So,what does the 1 section mean?It means a set X consist of these operands of a operator and every element of the set X is unsequenced with each other,they are unsequenced.The sentence 2 is similar to sentence 1,It just make the set X consist of these subexpression of a expression.

Those statements of binary operator + are described in [expr.additive] and these's nothing about sequence of operands in that section,So,the rules 1 performed on the operator.Hence,as the standard say that unsequence can overlap,what does it mean?It means that "the parts of each evaluation can even be interleaved together"(@Ben Voigt said in the comment).So,for ++i + ++i,it's typically of case:

If a side effect on a memory location 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, the behavior is undefined

So,int a = ++i + ++i is undefined behaviour,the key point of this question is to understand the below sentence:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

xmh0511
  • 7,010
  • 1
  • 9
  • 36