4

I am following the C++ primer 5th edition book as it was mentioned to be a good beginner friendly book to learn C++. As I proceeded to solve the exercise in chapter 4 I came across the question 4.33 in section 4.10. I am posting below the question as written in book:

Using Table 4.12 (p. 166) explain what the following expression does:

someValue ? ++x, ++y : --x, --y
 

The question was a bit confusing to me so I decided to look it over web and found a git repository containing solution that looks something similar to what I've typed below:

#include<iostream>

int main()
{
    int x = 1, y = 9;
    std::cout << (true ? ++x, ++y : --x, --y) << std::endl;
    std::cout << x << "\t" << y << std::endl;
    std::cout << (false ? ++x, ++y : --x, --y) << std::endl;
    std::cout << x << "\t" << y << std::endl;
    return 0;
}

My query is upon running the above code, why does the compiler shows 9 on it's first cout statement, i.e, on the following statement:

std::cout << (true ? ++x, ++y : --x, --y) << std::endl;

the output is 9. From what I know, comma operator evaluates and discards its left hand values and returns its left hand expression's value as its result, also the preincrement operator increments the operand's value and returns the incremented value. So shouldn't that code output 10, i.e., the ++x increments x to 2 and then the value is discarded and then the ++y increments y to 10 and then returns its value. Also when I use the brackets the output on the same statement changes to 10 and behaves as I expect it to behave, i.e., doing this:

std::cout << (true ? (++x, ++y) : (--x, --y)) << std::endl;

outputs 10. Also in the solution the behaviour is written as:--> Equivalent to: (some_Value ? ++x, ++y :--x), --y If true, return y; else, return --y.

but from what I understand it should be:--> - Equivalent to: (some_Value ? ++x, ++y :--x, --y) If true, return ++y; else, return --y.

ie, the placement of the bracket is what bothered me. I know this is a tiny difference but I don't want to get the concept wrong. Am I missing something here?

Vega
  • 27,856
  • 27
  • 95
  • 103
Jiaar
  • 60
  • 6
  • 1
    If adding parentheses changes the behavior, it's an "order of operations" issue. – Robert Harvey Oct 04 '20 at 15:21
  • I don't understand. I remember it was mentioned in the book that the order in which statements are evaluated is not guaranteed but there are some exceptions to it like comma operator which guarantees the order of evaluation. – Jiaar Oct 04 '20 at 15:27
  • 1
    @Jiaar I'm not sure how up to date the textbook is, but things have changed in c++17 (not with respect to your code though). You might want to read [this](https://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points). – cigien Oct 04 '20 at 15:50
  • Thank you for responding. My query has been answered. Thank you very much for taking the time to take a look at it. I really appreciate it. The link you sent is helpful too. If I may ask, is there any other book that you'd recommend for the updated contents and that is beginner friendly too? – Jiaar Oct 04 '20 at 16:00
  • @Jiaar *As I proceeded to solve the exercise in chapter 4* -- The solution to that problem is to fire the programmer who would write code like that. – PaulMcKenzie Oct 04 '20 at 16:25
  • @PaulMcKenzie haha, you're funny and right too but I really love the book. I think it's written that way to expose beginners like me towards such situations that may arise in our coding days ahead. – Jiaar Oct 04 '20 at 16:33

2 Answers2

5

This expression:

(true ? ++x, ++y : --x, --y)

is misleading with regards to what the false clause of ?: is. Putting parentheses in the right place gives:

( (true ? (++x, ++y) : --x), --y)
  // true ^^^^^^^^^^  
  //            false  ^^^                           

Now, since the condition of ? is true, x and y get incremented to 2 and 10 respectively, in that order. After the ?: is evaluated, y is decremented to 9, which is the result of the entire expression.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • does that mean that the comma after --x is behaving as a separator rather than as an operator?? – Jiaar Oct 04 '20 at 15:31
  • 1
    @Jiaar No, it's the comma operator that sequence the `?:` followed by the `--y`. – cigien Oct 04 '20 at 15:33
  • I see how that's working. I think I understand it now. Thank you taking the time to answer it and explaining so well. :) – Jiaar Oct 04 '20 at 15:36
  • @Jiaar No problem. Just to clarify, you can only accept at most *one* answer. You can still upvote all the answers you find useful. – cigien Oct 04 '20 at 15:38
  • 1
    I was wondering why it wasn't letting me accept both answers. Thanks once again :) – Jiaar Oct 04 '20 at 15:39
3

Although you are correct in your assumption that the order of evaluation of expressions separated by the comma operator is guaranteed (to be left-to-right), what you have not considered here is the priority of operators.

The comma operator has the lowest priority of all. So, the following:

    std::cout << (true ? ++x, ++y : --x, --y) << std::endl;

Is the equivalent of this (adding parentheses to show how the compiler sees things):

    std::cout << ( (true ? (++x, ++y) : --x), --y ) << std::endl;

Note that the parentheses around the first use of the comma operator are there because the compiler is already processing the ternary ? and evaluates the entire expression preceding the :, in 'one fell swoop'.

Thus after incrementing x and y, the code then decrements y - giving your output as the 'original' value.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83