2

So I came across this snippet of code in quora article to swap two numbers.

a = a + b - (b = a);

I tried this out and it worked fine. But since b = a is in parenthesis shouldn't b value be assigned the value of a first ? and the whole thing should become a + a - a making a to retain its value ?

I tried a = b + (b = a); with a = 5 b = 10 and I got a = 10 in the end. See here I guess it evaluated as a = a + a

Why this anomaly ?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Aditya
  • 1,240
  • 2
  • 14
  • 38
  • Parenthesis change the precedence of operators they contain; they don't change the order of operations. – Wooble Aug 06 '13 at 02:55
  • 1
    `UB` = [Undefined Behavior](http://en.wikipedia.org/wiki/Undefined_behavior) – Shafik Yaghmour Aug 06 '13 at 02:55
  • I tried it, it came out this way, ergo it will always come out this way is the root of the worst programming evils. – mattnz Aug 06 '13 at 03:20
  • @mattnz the only reason I answered is because other answers ignored my comments about the UB, there is still an answer there that is completely wrong – aaronman Aug 06 '13 at 03:21
  • @user2340452 C and C++ does not guarantee the order of evaluation unlike let's say Java where the JLS says they are evaluated from left to right, see this: http://stackoverflow.com/questions/17684991/difference-in-increment-decrement-operator-in-c-and-java – Shafik Yaghmour Aug 06 '13 at 14:52

3 Answers3

5

This is undefined behavior because of section 6.5.2 from the C99 draft standard which states:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.72) Furthermore, the prior value shall be read only to determine the value to be stored

In this case we are modifying b and using it's value to determine the result of a, the standard gives the following examples as undefined:

i = ++i + 1;
a[i++] = i;

cranking up warning at least in gcc would have alerted to a problem, using -W -Wall I receive the following warning:

warning: operation on ‘b’ may be undefined [-Wsequence-point]
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Would you be angry if I just copy pasted that standards quote into my answer, seems to be the key to votes – aaronman Aug 06 '13 at 03:27
  • @aaronman I would encourage you to download the draft standard which I linked in my answer, find the section I quote and try to understand it first and the relevant pieces around it. – Shafik Yaghmour Aug 06 '13 at 03:31
  • Why do you assume I don't understand it ;) – aaronman Aug 06 '13 at 03:31
  • @aaronman I try not to assume anything if I can help it ... obtaining your own copy and finding it for yourself will only help you learn more. – Shafik Yaghmour Aug 06 '13 at 03:35
  • I agree, I actually looked through the standard for like an hour for one of my own questions today, I do kind of dislike that standards quotes get so much attention on SO, IMO most of the time it is better to explain what's in the standard in layman's terms – aaronman Aug 06 '13 at 03:37
  • 3
    SO users are not laymen. The standards / language definition docs are the source, and are *carefully* written to be as clear and unambiguous as possible. Explanations *should* include quotes from the standard, so that the explanation does not become the source of misunderstanding. There is nothing more useless than a misleading or misunderstood explanation, unless it is one taken out of context. – andy256 Aug 06 '13 at 03:56
  • @andy256 every question does not need a standards quote to answer it, and by layman I mean people without an in depth knowledge of aspects of programming languages which is most of this site – aaronman Aug 06 '13 at 04:08
0

Precedence establishes what operands are linked by what operators. It does not establish order of evaluation.

The assignment operator has very low precedence. As a result, without the parentheses, the expression

a = a + b - b = a

would be parsed as:

(a) = (a + b - b) = (a)

This would result in an error, because (a + b - b) is not an lvalue. So the parentheses are required in order to group the two operands b and a with the assignment operator, as in your original statement:

a = a + b - (b = a)

But all the parentheses impose is the grouping, not the order of evaluation.

All you can be sure of is that whenever (b = a) is evaluated:

  1. the value of the entire expression will be the value of a
  2. As a side effect, b will be assigned the value of a.

When that will happen, however, is not predictable across compilers. The standard is explicit: in a complex expression, the order in which the subexpressions are evaluated and the order in which side-effects take place is unspecified, i.e., compiler dependent. The standard does not impose any requirements on the order in which subexpressions should be evaluated.

More generally, in C, if you modify a variable's value while using that variable elsewhere in the expression, the result you get will be undefined, which means anything could happen. You absolutely cannot rely on the expression a = a + b - (b = a), as it both modifies the value of b and uses the value of b elsewhere in the expression.

So the expression is evoking both unspecified behavior (relying on a specific order of evaluation) and undefined behavior (modifying a variable's value while using it elsewhere in the expression). Quite an impressive feat, when you think about it!

Edit: The above is true for C99. The latest standard, C11, explicitly calls this behavior undefined: "If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings." (6.5.2). The draft standard is available for free.

verbose
  • 7,827
  • 1
  • 25
  • 40
-1

As stated in the comments, it's Undefined behavior. the code is read straight from left-to-right instead of using PEMDAS.

mari0-k
  • 310
  • 2
  • 4