Grokking the comma operator [duplicate] - c++

This question already has answers here:
What does the comma operator , do?
(8 answers)
Is comma operator free from side effect?
(5 answers)
Closed 2 years ago.
I am trying to grok the comma operator. The reference says:
In a comma expression E1, E2, the expression E1 is evaluated, its result is discarded (...), and its side effects are completed before evaluation of the expression E2 begins (...).
I am unable to grok the clause - "... the expression E1 is evaluated, its result is discarded (...), and its side effects are completed before...". Specifically, what is retained and what is discarded?
For e.g., in the example from this SO answer:
int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
// Do something which uses a converging x and y
}
When we do a ++x, what is the 'result' (that is discarded) and what is the 'side-effect' (that is 'completed' and perhaps 'retained')? Shouldn't the result of ++x be discarded and the value of x remain unchanged? Working example showing incrementation of x is here.
In other words, given a certain expression, how do I deduce if it will be evaluated and its results would be discarded, or if it is a side-effect and its results would perhaps be computed and retained?

In C++ an expression can result in a value and can cause side effects. In the expression ++x, --y you have two sub expressions forming the whole expression. The left, ++x returns x after increment, and the right returns y after decrement. The expression will return the right side of the comma (y) rather than the left side x.
The side effects of the left hand side are preserved, so x is still incremented.
This might make more sense if you were looking to perform assignment.
For example
int x = 1;
int y = 1;
int& z = (++x, --y);
std::cout << z << std::endl;
z becomes a reference to y and thus we will print 0

Related

what is the concept of evaluation of expression z = (y = 30) + (y = 10) + (y = 20); [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
What is the output of the following code please help ... I'm not getting any compiler error
How does the compiler evaluate such expression?
#include <stdio.h>
int main()
{
int y = 3;
int z = (y = 30) + (y = 10) + (y = 20);
// `print z`
printf("%d\n", z);
// `print y`
printf("%d\n",y);
}
Strictly speaking, the behavior is undefined:
6.5 Expressions
...
2 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.84)
84) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;
C 2011 Online Draft
Similar language exists for C++.
C does not force left-to-right evaluation of arithmetic expressions - each of the y=30, y=10, and y=20 subexpressions may be evaluated in any order (a parallel architecture may evaluate them all simultaneously). Each of these expressions has a side effect - they change the value of y:
6.5.16 Assignment operators
...
3 An assignment operator stores a value in the object designated by the left operand. An
assignment expression has the value of the left operand after the assignment,111) but is not
an lvalue. The type of an assignment expression is the type the left operand would have
after lvalue conversion. The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands. The evaluations of
the operands are unsequenced.
111) The implementation is permitted to read the object to determine the value but is not required to, even
when the object has volatile-qualified type.
ibid.
Note that emphasized portion only specifies that the side effect is sequenced after evaluating the two operands - it doesn't say that it occurs immediately after. y may be updated immediately after each assignment, or it might not.
"But", I hear you say, "the result of y = 10 is 10 regardless of whether y is updated or not, so shouldn't the value stored in z be 60 irrespective of all that other stuff?"
That's the problem with undefined behavior - once any part of your program is undefined, the whole program is undefined. There are no guarantees of anything. z may get the value 60. It may get something else.
There's no way of predicting what the value of y should be at the end of this, either.

Post-increment operator behaviour w.r.t comma operator?

In the following code:
int main() {
int i, j;
j = 10;
i = (j++, j+100, 999+j);
cout << i;
return 0;
}
The output is 1010.
However shouldn't it be 1009, as ++ should be done after the whole expression is used?
The comma operator is a sequence point: as it says in the C++17 standard for example,
Every value computation and side effect associated with the left expression is sequenced
before every value computation and side effect associated with the right expression.
Thus, the effect of the ++ operator is guaranteed to occur before 999+j is evaluated.
++ should be done after the whole expression is used?
No. The postfix operator evaluates to the value of the old j and has the side effect of incrementing j.
Comma operator evaluates the second operand after the first operand is evaluated and its side-effects are evaluated.
A pair of expressions separated by a comma is evaluated left-to-right;
the left expression is a discarded- value expression (Clause 5)83.
Every value computation and side effect associated with the left
expression is sequenced before every value computation and side effect
associated with the right expression.
https://stackoverflow.com/a/7784819/2805305
Associativity of the comma operator is left to right.
So starting from j++, this will be evaluated first (j becomes 11)
Then j + 100 is evaluated (no use)
Then 999 + j is evaluated which is equal to 1010
This rightmost value is assigned to i
Thus, the output is 1010
Long Answer:
Built-in comma operator
The comma operator expressions have the form
E1 , E2
In a comma expression E1, E2, the expression E1 is evaluated, its
result is discarded (although if it has class type, it won't be
destroyed until the end of the containing full expression), and its
side effects are completed before evaluation of the expression E2
begins (note that a user-defined operator, cannot guarantee
sequencing) (until C++17).
This already answers your question, but I'll walk through it with reference to your code:
Start with something simple like
int value = (1 + 2, 2 + 3, 4 + 5); // value is assigned 9
Because ...the expression E1 is evaluated, its result is discarded... Here, since we have more than 2 operands, the associativity of the comma operator also comes into play.
However shouldn't it be 1009, as '++" should be done after the whole
expression is used?
Now see:
int j = 0;
int i = (j++, 9 + j);
Here, the value of i is 10 because ...and its side effects are completed before evaluation of the expression E2 begins... Hence, the incrementation of j has its effect before the evaluation of 9 + j.
I think now you can clearly understand why your
j = 10;
i = (j++, j+100, 999+j);
i is assigned a value of 1010.

Why does the ternary operator with commas evaluate only one expression in the true case?

I'm currently learning C++ with the book C++ Primer and one of the exercises in the book is:
Explain what the following expression does: someValue ? ++x, ++y : --x, --y
What do we know? We know that the ternary operator has a higher precedence than the comma operator. With binary operators this was quite easy to understand, but with the ternary operator I am struggling a bit. With binary operators "having higher precedence" means that we can use parentheses around the expression with higher precedence and it will not change the execution.
For the ternary operator I would do:
(someValue ? ++x, ++y : --x, --y)
effectively resulting in the same code which does not help me in understanding how the compiler will group the code.
However, from testing with a C++ compiler I know that the expression compiles and I do not know what a : operator could stand for by itself. So the compiler seems to interpret the ternary operator correctly.
Then I executed the program in two ways:
#include <iostream>
int main()
{
bool someValue = true;
int x = 10, y = 10;
someValue ? ++x, ++y : --x, --y;
std::cout << x << " " << y << std::endl;
return 0;
}
Results in:
11 10
While on the other hand with someValue = false it prints:
9 9
Why would the C++ compiler generate code that for the true-branch of the ternary operator only increments x, while for the false-branch of the ternary it decrements both x and y?
I even went as far as putting parentheses around the true-branch like this:
someValue ? (++x, ++y) : --x, --y;
but it still results in 11 10.
As #Rakete said in their excellent answer, this is tricky. I'd like to add on to that a little.
The ternary operator must have the form:
logical-or-expression ? expression : assignment-expression
So we have the following mappings:
someValue : logical-or-expression
++x, ++y : expression
??? is assignment-expression --x, --y or only --x?
In fact it is only --x because an assignment expression cannot be parsed as two expressions separated by a comma (according to C++'s grammar rules), so --x, --y cannot be treated as an assignment expression.
Which results in the ternary (conditional) expression portion to look like this:
someValue?++x,++y:--x
It may help for readability's sake to consider ++x,++y to be computed as-if parenthesized (++x,++y); anything contained between ? and : will be sequenced after the conditional. (I'll parenthesize them for the rest of the post).
and evaluated in this order:
someValue?
(++x,++y) or --x (depending on boolresult of 1.)
This expression is then treated as the left sub-expression to a comma operator, with the right sub-expression being --y, like so:
(someValue?(++x,++y):--x), --y;
Which means the left side is a discarded-value expression, meaning that it is definitely evaluated, but then we evaluate the right side and return that.
So what happens when someValue is true?
(someValue?(++x,++y):--x) executes and increments x and y to be 11 and 11
The left expression is discarded (though the side effects of increment remain)
We evaluate the right hand side of the comma operator: --y, which then decrements y back to 10
To "fix" the behavior, you can group --x, --y with parentheses to transform it into a primary expression which is a valid entry for an assignment-expression*:
someValue?++x,++y:(--x, --y);
*It's a rather funny long chain that connects an assignment-expression back to a primary expression:
assignment-expression ---(can consist of)--> conditional-expression --> logical-or-expression --> logical-and-expression --> inclusive-or-expression --> exclusive-or-expression --> and-expression --> equality-expression --> relational-expression --> shift-expression --> additive-expression --> multiplicative-expression --> pm-expression --> cast-expression --> unary-expression --> postfix-expression --> primary-expression
Wow, that's tricky.
The compiler sees your expression as:
(someValue ? (++x, ++y) : --x), --y;
The ternary operator needs a :, it cannot stand by itself in that context, but after it, there is no reason why the comma should belong to the false case.
Now it might make more sense why you get that output. If someValue is true, then ++x, ++y and --y get executed, which doesn't effectively change y but adds one to x.
If someValue is false, then --x and --y are executed, decrementing them both by one.
Why would the C++ compiler generate code that for the true-branch of the ternary operator only increments x
You misinterpreted what has happened. The true-branch increments both x and y. However, y is decremented immediately after that, unconditionally.
Here is how this happens: since the conditional operator has higher precedence than comma operator in C++, the compiler parses the expression as follows:
(someValue ? ++x, ++y : --x), (--y);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
Note the "orphaned" --y after the comma. This is what leads to decrementing y that has been initially incremented.
I even went as far as putting parentheses around the true-branch like this:
someValue ? (++x, ++y) : --x, --y;
You were on the right path, but you parenthesized a wrong branch: you can fix this by parenthesizing the else-branch, like this:
someValue ? ++x, ++y : (--x, --y);
Demo (prints 11 11)
Your problem is that the ternary expression doesn't really have higher precedence than comma. In fact, C++ can't be described accurately simply by precedence - and it is exactly the interaction between the ternary operator and comma where it breaks down.
a ? b++, c++ : d++
is treated as:
a ? (b++, c++) : d++
(comma behaves as if it has higher precedence). On the other hand,
a ? b++ : c++, d++
is treated as:
(a ? b++ : c++), d++
and the ternary operator is higher precedence.
A point that's been overlooked in answers (though touched on comments) is that the conditional operator is invariably used (intended by design?) in real code as a shortcut for assigning one of two values to a variable.
So, the larger context would be:
whatIreallyWanted = someValue ? ++x, ++y : --x, --y;
Which is absurd on its face, so the crimes are manifold:
The language permits ridiculous side effects in an assignment.
The compiler didn't warn you that you were doing bizarre things.
The book appears to be focusing on 'trick' questions. One can only hope that the answer in the back was "What this expression does is depend on weird edge cases in a contrived example to produce side effects that nobody expects. Never do this."

C - What does x+1 means without assignment?

My question is maybe very simple, but I'm wondering what does this x+1 means?
Let's see an example:
int main()
{
int x = 2;
x + 1; //1
if ((x - 2) && (x = 7)) { //2 and 3
// do something
}
}
What i know:
That the assignment cannot be evaluated because left side of && will return false, so the conjunction will never be true.
Questions:
How does the memory looks like after operation 1?
Is the value of x changed after x-2 (2)?
I saw in debugger that this doesn't change the value of x, but I'm using a C++ compiler in Visual Studio so it can give another values.
Thanks in advance :)
The code
x+1;
evaluates the expression and then just drops the results. It's legal but a good compiler should issue a warning (IIRC g++ emits something about an expression that would require side effects to be useful).
The code (x - 2) && (x = 7) instead doesn't do anything, because && is "short-circuited" and x-2 is false in a logical context. So the code (x = 7) is not evaluated. && and || evaluate the left side first and the right side is evaluated only if the result cannot be determined from it... for example (1 || foo()) is guaranteed to skip the call to function foo.
Code like
y = (x - 2) * (x = 7);
would instead be undefined behavior because C++ is not required to work through sub-expressions in sequence (except for the comma operator ,, logical AND &&, logical OR|| and the ternary operator ?:) and using and modifying the same value in different parts of an expression (if these parts don't have a prescribed evaluation sequence) is not permitted but the compilers are not required to complain about it. Whatever happens happens, and it's a programmer's fault.
How does the memory looks like after operation 1?
It's the same as before the operation. x - 1 is an expression without side-effects (i.e. it doesn't modify any variable). The statement x - 1; evaluates the expression and discards the result. Any decent compiler will optimize it away.
To increment x by 1 you should use the compound assignment operator +=:
x += 1;
The same can be achieved with the increment operator ++:
x++; // these do the same
++x; // thing in this case
In other contexts, the two different versions of ++ have different meaning, see What is the difference between prefix and postfix operators?.
Is the value of x changed after x-2 (2)?
x - 2 itself doesn't change the value of x. (Again x -= 2 can be used to achieve that.)
However the assignment x = 7 changes the value of x to 7, if the assignment is evaluated (which happens if the left-hand-side of && evaluates to true or non-zero (this is called short-circuit evaluation). In this case the left-hand-side evaluates to zero so x = 7 is not evaluated).
Note that the = operator is different to the equality comparison operator ==:
x == 7 // evaluates to `true` if the value of `x` is equal to `7`, and to `false` otherwise.
It means "perform this calculation and throw away the result".
In your case that means the compiler will probably just remove the code completely (since it obviously has no side effects). But if operator+ had been overloaded and/or user-defined types had been involved, then there could be meaningful side-effects and the code could be meaningfull and would be kept to perform those operations..
x + 1 does not change value of x. The result of x + 1 viz 3 is calculated and the result is then ignored.
For and (&&) sequence of evaluation is left to right. As long as the components of && operator are true, the next component is evaluated.
As stated earlier for x + 1, similarly, x + 2 does not change value of x. In your case, x - 2 results into 0 viz. zero and so the next component is not evaluated.
The basic principles of C language, remain same across all compilers and IDE (in your case Visual Studio) has no effect on the compilation

Post-increment and Pre-increment concept?

I don't understand the concept of postfix and prefix increment or decrement. Can anyone give a better explanation?
All four answers so far are incorrect, in that they assert a specific order of events.
Believing that "urban legend" has led many a novice (and professional) astray, to wit, the endless stream of questions about Undefined Behavior in expressions.
So.
For the built-in C++ prefix operator,
++x
increments x and produces (as the expression's result) x as an lvalue, while
x++
increments x and produces (as the expression's result) the original value of x.
In particular, for x++ there is no no time ordering implied for the increment and production of original value of x. The compiler is free to emit machine code that produces the original value of x, e.g. it might be present in some register, and that delays the increment until the end of the expression (next sequence point).
Folks who incorrectly believe the increment must come first, and they are many, often conclude from that certain expressions must have well defined effect, when they actually have Undefined Behavior.
int i, x;
i = 2;
x = ++i;
// now i = 3, x = 3
i = 2;
x = i++;
// now i = 3, x = 2
'Post' means after - that is, the increment is done after the variable is read. 'Pre' means before - so the variable value is incremented first, then used in the expression.
The difference between the postfix increment, x++, and the prefix increment, ++x, is precisely in how the two operators evaluate their operands. The postfix increment conceptually copies the operand in memory, increments the original operand and finally yields the value of the copy. I think this is best illustrated by implementing the operator in code:
int operator ++ (int& n) // postfix increment
{
int tmp = n;
n = n + 1;
return tmp;
}
The above code will not compile because you can't re-define operators for primitive types. The compiler also can't tell here we're defining a postfix operator rather than prefix, but let's pretend this is correct and valid C++. You can see that the postfix operator indeed acts on its operand, but it returns the old value prior to the increment, so the result of the expression x++ is the value prior to the increment. x, however, is incremented.
The prefix increment increments its operand as well, but it yields the value of the operand after the increment:
int& operator ++ (int& n)
{
n = n + 1;
return n;
}
This means that the expression ++x evaluates to the value of x after the increment.
It's easy to think that the expression ++x is therefore equivalent to the assignmnet (x=x+1). This is not precisely so, however, because an increment is an operation that can mean different things in different contexts. In the case of a simple primitive integer, indeed ++x is substitutable for (x=x+1). But in the case of a class-type, such as an iterator of a linked list, a prefix increment of the iterator most definitely does not mean "adding one to the object".
No one has answered the question:
Why is this concept confusing?
As an undergrad Computer Science major it took me awhile to understand this because of the way I read the code.
The following is not correct!
x = y++
X is equal to y post increment. Which would logically seem to mean X is equal to the value of Y after the increment operation is done. Post meaning after.
or
x = ++y
X is equal to y pre-increment. Which would logically seem to mean X is equal to the value of Y before the increment operation is done. Pre meaning before.
The way it works is actually the opposite. This concept is confusing because the language is misleading. In this case we cannot use the words to define the behavior.
x=++y is actually read as X is equal to the value of Y after the increment.
x=y++ is actually read as X is equal to the value of Y before the increment.
The words pre and post are backwards with respect to semantics of English. They only mean where the ++ is in relation Y. Nothing more.
Personally, if I had the choice I would switch the meanings of ++y and y++. This is just an example of a idiom that I had to learn.
If there is a method to this madness I'd like to know in simple terms.
Thanks for reading.
It's pretty simple. Both will increment the value of a variable. The following two lines are equal:
x++;
++x;
The difference is if you are using the value of a variable being incremented:
x = y++;
x = ++y;
Here, both lines increment the value of y by one. However, the first one assigns the value of y before the increment to x, and the second one assigns the value of y after the increment to x.
So there's only a difference when the increment is also being used as an expression. The post-increment increments after returning the value. The pre-increment increments before.
int i = 1;
int j = 1;
int k = i++; // post increment
int l = ++j; // pre increment
std::cout << k; // prints 1
std::cout << l; // prints 2
Post increment implies the value i is incremented after it has been assigned to k. However, pre increment implies the value j is incremented before it is assigned to l.
The same applies for decrement.
Post-increment:
int x, y, z;
x = 1;
y = x++; //this means: y is assigned the x value first, then increase the value of x by 1. Thus y is 1;
z = x; //the value of x in this line and the rest is 2 because it was increased by 1 in the above line. Thus z is 2.
Pre-increment:
int x, y, z;
x = 1;
y = ++x; //this means: increase the value of x by 1 first, then assign the value of x to y. The value of x in this line and the rest is 2. Thus y is 2.
z = x; //the value of x in this line is 2 as stated above. Thus z is 2.
Since we now have inline javascript snippets I might as well add an interactive example of pre and pos increment. It's not C++ but the concept stays the same.
let A = 1;
let B = 1;
console.log('A++ === 2', A++ === 2);
console.log('++B === 2', ++B === 2);
From the C99 standard (C++ should be the same, barring strange overloading)
6.5.2.4 Postfix increment and decrement operators
Constraints
1 The operand of the postfix increment
or decrement operator shall have
qualified or unqualified real or
pointer type and shall be a modifiable
lvalue.
Semantics
2 The result of the postfix ++
operator is the value of the operand.
After the result is obtained, the
value of the operand is incremented.
(That is, the value 1 of the
appropriate type is added to it.) See
the discussions of additive operators
and compound assignment for
information on constraints, types, and
conversions and the effects of
operations on pointers. The side
effect of updating the stored value of
the operand shall occur between the
previous and the next sequence point.
3 The postfix -- operator is analogous
to the postfix ++ operator, except
that the value of the operand is
decremented (that is, the value 1 of
the appropriate type is subtracted
from it).
6.5.3.1 Prefix increment and decrement operators
Constraints
1 The operand of the prefix increment
or decrement operator shall have
qualified or unqualified real or
pointer type and shall be a modifiable
lvalue.
Semantics
2 The value of the operand of the
prefix ++ operator is incremented. The
result is the new value of the operand
after incrementation. The expression
++E is equivalent to (E+=1). See the discussions of additive operators and
compound assignment for information on
constraints, types, side effects, and
conversions and the effects of
operations on pointers.
3 The prefix -- operator is analogous
to the prefix ++ operator, except that
the value of the operand is
decremented.
Post increment(a++)
If
int b = a++,then this means
int b = a;
a = a+1;
Here we add 1 to the value. The value is returned before the increment is made,
For eg a = 1; b = a++;
Then b=1 and a=2
Pre-increment (++a)
If int b = ++a; then this means
a=a+1;
int b=a ;
Pre-increment: This will add 1 to the main value. The value will be returned after the increment is made, For a = 1; b = ++a;
Then b=2 and a=2.
Already good answers here, but as usual there seems to be some general lack of clarity in simply remembering which way round these work. I suppose this arises because semantically resolving the nomenclature is not entirely straightforward. For example, you may be aware that "pre-" means "before". But does the pre-increment ++i return the value of i before the increment, or does it increment i before returning a value?
I find it much easier to visually follow the expression through from left to right:
++ i
-------------------------------------------------->
Increment i Then supply the value of i
i ++
-------------------------------------------------->
Supply the value of i Then increment i
Of course, as Alf points out in the accepted answer, this may not reflect when the 'real i' is updated, but it is a convenient way of thinking about what gets supplied to the expression.
#include<stdio.h>
void main(){
char arr[] ="abcd";
char *p=arr,*q=arr;
char k,temp;
temp = *p++; /* here first it assigns value present in address which
is hold by p and then p points to next address.*/
k = ++*q;/*here increments the value present in address which is
hold by q and assigns to k and also stores the incremented value in the same
address location. that why *q will get 'h'.*/
printf("k is %c\n",k); //output: k is h
printf("temp is %c\n",temp);//output: temp is g
printf("*p is %c\n",*p);//output: *p is e
printf("*q is %c",*q);//output: *q is h
}
Post and Pre Increment with Pointers
The pre increment is before increment value ++ e.g.:
(++v) or 1 + v
The post increment is after increment the value ++ e.g.:
(rmv++) or rmv + 1
Program:
int rmv = 10, vivek = 10;
cout << "rmv++ = " << rmv++ << endl; // the value is 10
cout << "++vivek = " << ++vivek; // the value is 11
You should also be aware that the behaviour of postincrement/decrement operators is different in C/C++ and Java.
Given
int a=1;
in C/C++ the expression
a++ + a++ + a++
evaluates to 3, while in Java it evaluates to 6. Guess why...
This example is even more confusing:
cout << a++ + a++ + a++ << "<->" << a++ + a++ ;
prints 9<->2 !! This is because the above expression is equivalent to:
operator<<(
operator<<(
operator<<( cout, a++ + a++ ),
"<->"
),
a++ + a++ + a++
)