This has been asked in an interview. What is the output of the below snippet?
#include <iostream>
using namespace std;
int main() {
cout << (3,2,1)-(1,2,3) << endl; // in C++ too this prints -2
printf("%d\n",(3,2,1)-(1,2,3)); // prints -2
printf("%d\n",("%d",3,2,1)-(1,2,3)); // prints -2
return 0;
}
By the output I am guessing its (1-3) = -2. But how from (3,2,1) value 1 is chosen, similarly from (1,2,3) value 3 is chosen? Am I right in what I am guessing?
Here, the comma operator and it's property is being used.
To elaborate, from C11, chapter §6.5.17, Comma operator
The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value
and, from C++11, chapter § 5.18,
A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause 5). 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. The type and value of the result are the type and value of the right operand; the result is of the same value category
as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field.
So, in case of a statement like
(3,2,1)-(1,2,3)
for the evaluation,
(3,2,1), 3 and 2 are (evaluated as a void expression and) discarded, 1 is the value.
(1,2,3), 1 and 2 are (evaluated as a void expression and) discarded, 3 is the value.
so, the statement reduces to 1 - 3 which is equal to -2.
Same way, you can use for more elements, also.
(3,2,1) means to calculate all the expressions and return last.
So, it does:
3 - nothing
2 - nothing
1 - return 1
And other:
1 - nothing
2 - nothing
3 - return 3
so your
cout << (3,2,1)-(1,2,3) << endl;
means:
cout << 1 - 3 << endl;
You have to consider the comma operator (,)
The comma operator (,) is used to separate two or more expressions
that are included where only one expression is expected. When the set
of expressions has to be evaluated for a value, only the right-most
expression is considered.
In your case:
(3,2,1) //evaluates to 1
(1,2,3) //evaluates to 3
source:
http://www.cplusplus.com/doc/tutorial/operators/
Comma operator always returns the last value i.e.
in your first cout it is 1-3=-2
next, in printf again it is 1-3=-3
finally in last printf, it is again 1-3=-2
Comma operator always solves all the left expressions(operands) and just returns the rightmost operand as result as rvalue.
Related
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.
This question already has answers here:
What's the precedence of comma operator inside conditional operator in C++?
(3 answers)
Closed 6 years ago.
int a,b;
a = 1 ? 1,2 : 3,4; // a = 2
b = 0 ? 1,2 : 3,4; // b = 3
Comma operator returns always the right side of comma, but if we make an assignment to variable it returns left except the case when we use ().
So how the hell the first expression gives the 2.
I see it as a = 1,2 so it should be 1 but actually a=2.
Why?
Due to operator precedence (comma operator having least precedence), your code actually looks like
int a,b;
(a = 1 ? (1,2) : 3),4; // a = 2
(b = 0 ? (1,2) : 3),4; // b = 3
So, as per the ternary condition rule, quoting C11, chapter §6.5.15
The first operand is evaluated; there is a sequence point between its evaluation and the
evaluation of the second or third operand (whichever is evaluated). The second operand
is evaluated only if the first compares unequal to 0; the third operand is evaluated only if
the first compares equal to 0; the result is the value of the second or third operand
(whichever is evaluated), converted to the type described below. 110)
[...]
110) A conditional expression does not yield an lvalue.
For first case, the second operand is evaluated and returned.
For second case, the third operand is evaluated and returned.
Recently I came across this piece of code. I don't know why I never saw this kind of syntax in all my "coding life".
int main()
{
int b;
int a = (b=5, b + 5);
std::cout << a << std::endl;
}
a has value of 10. What exactly is this way of initialization called? How does it work?
This statement:
int a = (b=5, b + 5);
Makes use of the comma operator. Per Paragraph 5.18/1 of the C++11 Standard:
[...] 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. The type
and value of the result are the type and value of the right operand; the result is of the same value category
as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field. If the value of the right
operand is a temporary (12.2), the result is that temporary.
Therefore, your statement is equivalent to:
b = 5;
int a = b + 5;
Personally, I do not see a reason for using the comma operator here. Just initialize your variable the easily readable way, unless you have a good reason for doing otherwise.
operator , evaluates arguments one after another and return the last value
It may be used not only in initialization
The comma , operator allows you to separate expressions. The compount statement made by
exp1, exp2, ..., expn
evaluates to expn.
So what happens is that first b is set to 5 and then a is set to b + 5.
A side note: since , has the lowest precedence in the table of operators the semantics of
int a = b = 5, b+5;
is different from
int a = (b = 5, b+5);
because the first is parsed as (int a = b = 5), b + 5
When used in an expression the comma operator will evaluate all of its operands (left-to-right) and return the last.
The initialization is called copy initialization. If you ignore the complex expression on the right, it's the same as in:
int a = 10;
This is to be contrasted with direct initialization, which looks like this:
int a(10);
(It's possible that you were separately confused about how to evalue a comma expression. Please indicate if that's the case.)
1.)
int i;
for(i=1;i<5,i<8;i++){
}
printf("%d",i);
2.)
int i;
for(i=1;i<18,i<6;i++){
}
printf("%d",i);
output for 1.) is 8 while for 2.) is 6
I am not getting how the code works, Help will be highly appreciated.
The , operator evaluates to its last operand.
i < 18, i < 6 becomes false when i is 6.
Comma operator ( , )
The comma operator (,) is used to separate two or more expressions that are included where only one expression is expected. When the set of expressions has to be evaluated for a value, only the rightmost expression is considered.
Hence:
for(i=1;i<5,i<8;i++)
is equivalent to:
for(i=1;i<8;i++)
Which evaluates value of i to 8
And
for(i=1;i<18,i<6;i++)
is equivalent to:
for(i=1;i<6;i++)
Which evaluates value of i to 6
Standerdese Reference:
C++11 Standard §5.18:
The comma operator groups left-to-right.
expression:
assignment-expression
expression , assignment-expression
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. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field.
For example for such statement:
c += 2, c -= 1
Is it true that c += 2 will be always evaluated first, and c in second expression c-= 1 will always be updated value from expression c += 2?
Yes, it is guaranteed by the standard, as long as that comma is a non-overloaded comma operator. Quoting n3290 §5.18:
The comma operator groups left-to-right.
expression:
assignment-expression
expression , assignment-expression
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. The type
and value of the result are the type and value of the right operand; the result is of the same value category
as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field.
And the corresponding footnote:
83 However, an invocation of an overloaded comma operator is an ordinary function call; hence, the evaluations of its argument
expressions are unsequenced relative to one another (see 1.9).
So this holds only for the non-overloaded comma operator.
The , between arguments to a function are not comma operators. This rule does not apply there either.
For C++03, the situation is similar:
The comma operator groups left-to-right.
expression:
assignment-expression
expression , assignment-expression
A pair of expressions separated by a comma is evaluated left-to-right and the value of the left expression is
discarded. The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conver-
sions are not applied to the left expression. All side effects (1.9) of the left expression, except for the
destruction of temporaries (12.2), are performed before the evaluation of the right expression. The type and
value of the result are the type and value of the right operand; the result is an lvalue if its right operand is.
Restrictions are the same though: does not apply to overloaded comma operators, or function argument lists.
Yes, the comma operator guarantees that the statements are evaluated in left-to-right order, and the returned value is the evaluated rightmost statement.
Be aware, however, that the comma in some contexts is not the comma operator. For example, the above is not guaranteed for function argument lists.
Yes, in C++ the comma operator is a sequence point and those expression will be evaluated in the order they are written. See 5.18 in the current working draft:
[snip] is evaluated left-to-right. [snip]
I feel that your question is lacking some explanation as to what you mean by "side effects". Every statement in C++ is allowed to have a side effect and so is an overloaded comma operator.
Why is the statement you have written not valid in a function call?
It's all about sequence points. In C++ and C it is forbidden to modify a value twice inside between two sequence points. If your example truly uses operator, every self-assignment is inside its own sequence point. If you use it like this foo(c += 2, c -= 2) the order of evaluation is undefined. I'm actually unsure if the second case is undefined behaviour as I do not know if an argument list is one or many sequence points. I ought to ask a question about this.
It should be always evaluated from left to right, as this is the in the definition of the comma operator:
Link
You've got two questions.
The first question: "Is comma operator free from side effect?"
The answer to this is no. The comma operator naturally facilitates writing expressions with side effects, and deliberately writing expressions with side effects is what the operator is commonly used for. E.g., in while (cin >> str, str != "exit") the state of the input stream is changed, which is an intentional side effect.
But maybe you don't mean side-effect in the computer science sense, but in some ad hoc sense.
Your second question: "For example for such statement: c += 2, c -= 1 Is it true that c += 2 will be always evaluated first, and c in second expression c-= 1 will always be updated value from expression c += 2?"
The answer to this is yes in the case of a statement or expression, except when the comma operator is overloaded (very unusual). However, sequences like c += 2, c -= 1 can also occur in argument lists, in which case, what you've got is not an expression, and the comma is not a sequence operator, and the order of evaluation is not defined. In foo(c += 2, c -= 1) the comma is not a comma operator, but in foo((c += 2, c -= 1)) it is, so it may pay to pay attention to the parentheses in function calls.