Can I write? a = (b = 5, c = 10);
And if it's possible, please, calculate this expression... I have no idea what a comma between expressions and expressions is.
comma calculates the left side (b=5),then calculates the right side (c=10),then returns the result of ther right side (reference to c).
There are several online compilers available if you want to test if something compiles or what it evaluates to: http://ideone.com , http://liveworkspace.org and others.
comma calculates the left side (b=5),then calculates the right side (c=10)
I'm nearly certain the order is undefined.
Of course I could be wrong. I know it's undefined for most binary operators. I thought the only exception was for || and && to allow for short circuiting.
I understand the implications. I just didn't realize comma was defined that way when pretty much everything else isn't. It's just a little surprising to me... but I guess it kind of makes sense.
VolatilePulse wrote:
@Disch
What other binary operators don't have their order defined?
int a = 1;
// this results in undefined behavior because the order in which
// 'a' and '++a' are evaluated is undefined:
int b = (++a + a);
// this, however, is apparently perfectly OK and is defined,
// which is what surprised me:
int c = (++a, a);
EDIT:
To add to the confusion... the comma operator apparently ISN'T defined when it's used in a parameter list.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int junk(int a, int b)
{
cout << a << " " << b << "\n";
return 5;
}
int main()
{
int v = 1;
junk( ++v, ++v ); // prints "3 3" on my system, illustrating undefined behavior
cin.get();
}
So the comma operator used to separate arguments must not be the same comma operator used to separate other expressions. Which makes it even more confusing why they made the special case for the comma operator....
I understand it might not be defined by the standard, but logically, that makes perfect sense. The prefix increment operator is evaluated before the value of v is. Once both operators are evaluated, the variable can be evaluated for the call stack (right? the call stack?).
Same goes for (++a + a). increment operators take precedence over mathematical operators so we evaluate the increment operator, then the mathematical operator. The only time I could see some confusion would be the behavior of the postfix versions.
I also believe most of the operators have defined behavior, however, they're not meant to be linked together. You try hard enough to break something, it'll eventually give. The order of precedence plays a huge role, however, I don't know what they are, and when mixed with operators of a different class is when undefined behavior comes into play.
I also believe most of the operators have defined behavior, however, they're not meant to be linked together. You try hard enough to break something, it'll eventually give.
The operators have clearly defined behavior. And the order of precedence is clearly defined. What isn't defined is the order in which expressions on either side of an operator are evaluated before the operator itself is evaluated.
Example:
a + b * c;
The following are clearly defined by the language:
- 'b' will be evaluated before '*'
- 'c' will be evaluated before '*'
- 'a' will be evaluated before '+'
- '*' will be evaluated before '+'
However the order of anything outside of that is undefined. The compiler may evaluate in any of the below orders:
b, c, *, a, +
c, b, a, *, +
a, c, b, *, +
c, b, *, a, +
etc
JLBorges wrote:
There, the comma is not an operator, it is a separator
Fair enough... I guess my terminology was incorrect. Still is confusing/questionable though.
Anyway I understand, so I don't know if we need to drag this out more. I just thought it was strange, is all.
int b = 5, c = 10;
int a = ( b++, c++, b + c );
std::cout << "a = " << a << std::endl;
// Evaluates to
int b = 5;
int c = 10;
b ++; // 6
c ++; // 11
int a = b + c; // 17
std::cout << "a = " << a << std::endl; // a = 17
////////////////////////////////////////////////////////////////////////////////
staticint b;
int a = ( b++, b++, b++ );
std::cout << "a = " << a << std::endl;
// Evaluates to
staticint b; // Not sure why you use static, but should be initialized to 0
// Assuming ints are initialized to 0
b ++; // 1
b ++; // 2
int a = b++; // a = 2 | b = 3
std::cout << "a = " << a << std::endl; // a = 2
////////////////////////////////////////////////////////////////////////////////
int f()
{
staticint b;
return ( b++, b++, b++ );
}
int main()
{
int a = ( f(), f() );
std::cout << "a = " << a << std::endl;
}
// Evaluates to
// 1st call to f
staticint b; // Again assuming implementation of ints is 0
// b = 0;
b ++; // 1
b ++; // 2
return b ++; // 2 is returned | b = 3
// 2nd call to f
b; // 3
b ++; // 4
b ++; // 5
return b ++; // 5 is returned | b = 6
// Returning to main
int a = 5; // a is assigned the last expression in the comma operator
std::cout << "a = " << a << std::endl; // a = 5;
////////////////////////////////////////////////////////////////////////////////
int main()
{
struct B
{
intoperator ()() const
{
staticint b;
return ( b++, b++, b++ );
}
} b;
int a = ( b(), b() );
std::cout << "a = " << a << std::endl;
}
// Evaluates to essentially the same as above
std::cout << "a = " << a << std::endl; // a = 5
@JLBorges
The comma is only a separator in arguments, nothing else. In all other situations, it's an operator.
Edit: You're introducing the () operator in your second call, which is evaluated first, which in turns only passes one argument.
int junk(int a, int b)
{
cout << a << " " << b << "\n";
return 5;
}
int main()
{
int v = 1;
junk( ++v, ++v ); // prints "3 3" on my system, illustrating undefined behavior
cin.get();
}
// Evaluates to
int v = 1; // 1
++ v; // 2
++ v; // 3
junk (3, 3);
cout << a << " " << b << "\n"; // 3 3
@Disch
Here is your example with a bit of a twist on it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
int a = 1, b = 2, c = 3;
++ a + ++ b * c ++;
// Evaluates to
// - 'b' will be evaluated before '*'
// - 'c' will be evaluated before '*'
// - 'a' will be evaluated before '+'
// - '*' will be evaluated before '+'
// Following the above logic, the equation can be rewritten like so
(++ a) + ((++ b) * (c ++));
(++ a) + ((3) * (c ++)); // prefix increment, b is increased and returned | 3
(++ a) + ((3) * (3)); // postfix increment, c is returned but then increased | 4
(2) + ((3) * (3)); // prefix increment, a is increased and returned | 2
(2) + (9); // multiplication first
(11); // addition
Keeping it reasonable to factor out, there isn't anything you guys can give me that doesn't logically make sense. I believe the only reason it isn't defined is because it's probably hard for tell a computer how to do all of the stuff (on large scales) or just to keep people from being dumb, so when they expect something different, it can be blamed on implementation defined and not standard defined.
Try running the above example and see if you get 11 as well.
I'm in the mood for challenges, so I'd like to see what you guys can come up with.
@Volatile Pulse
The result of ++ a + ++ b * c ++; in your latest example is well defined. It will always give you 11. It doesn't matter in what order the sub-expressions are evaluated.
The comma is an operator only when used as part of an expression, and nowhere else.
In all other situations, it's a separator.
In all but the first example, I'd definitely consider them arguments. Arguments to a template, arguments to an array initialization, arguments to an object initialization. The first example is still an expression to me, each piece gets evaluated separately. The only difference is that you're declaring something. If you use the comma operator during declaration, it separates the expression, and makes each part of the expression declared as the data type you declared the first one as. Try this for example:
for (auto i = 1, it = myVec.begin();...) // *ERROR*
Refer to above response
@Peter87
From the way Disch explained it, it sounded like no possible way it could be defined to always be true. Is there a variation of that that isn't defined?
The problem is when you use the same variable more than once in the same expression and the variable is modified at least once. This is the case with ++a + a. if a is 1 and ++a is evaluated before a you get 2 + 2. If instead a is evaluated before ++a you get 2 + 1. The standard says the result is undefined so you could get something completely different, but I hope this helps understanding the problem.