C/C++ comma operator puzzles me. Language lawyers? - c++

I came across this bit of code in an example from the Boost documentation:
std::vector<int> input;
input += 1,2,3,4,5,6,7,8,9;
How cute. Boost has a template for operator+= that takes advantage of the fact that the comma is, under most circumstances, an operator. (Wisely, C++ does not allow a hackist to overload "operator,".)
I like to write cute code too, so I played around some with the comma-operator. I found something that looks weird to me. What do you think the following code will print?
#include <iostream>
int main() {
int i;
i = 1,2;
std::cout << i << ' ';
i = (1,2);
std::cout << i << std::endl;
}
You guessed it. VC++ 2012 prints "1, 2". What's up with that?
[Edit: I should have been more precise. Should have said C++ does not allow operator "," in a list of int's to be overloaded. Or better yet, nothing. The ',' operator can be overloaded for classes and enums.]

CASE 1:
i = 1,2;
= has higher precedence than ,
hence, 1 is assigned to i.
Since assignment evaluates to an lvalue in c++,(evaluates to rvalue in c) it becomes i,2 which evaluates to2 (refer NOTE)
CASE 2:
i = (1,2);
() has higher precedence than =
expressions or operands separated by , operator evaluates to the value of the last expression or operand hence, 2 is assigned to i
NOTE
a comma expression like 33,77,x,y,z is evaluated from left to right.
The result of such comma expression is the value of rightmost expression .
Examples
Consider, int z=100;
then
1,4,5; //evaluates to 5
1,100,z+100; //evaluates to 200

Simple: "=" has higher precendence.
i = 1,2;
Is like (i=1),2, meaning the result of the expression is 2 but it's discarded.
i = (1,2);
The result of (1,2) is 2.
EDIT: this might be so things like
for (i=0, j=0; ...)
work as expected.

Related

Why do I have to enclose bitwise operators, such as &,|,etc in a bracket, when I am displaying the output using cout?

I am trying to display the output of bitwise operations directly through cout stream.
I am getting an error in such situations:
cout<<a|b
However, this seems to work,
cout<<(a|b);
In the case of arithmetic operations,
cout<<a+b;
and
cout<<(a+b);
works fine.
Note: I am considering a and b to be integers.
For example,
int a = 5;
int b = 6;
Can someone explain the reason behind this?
<< is also an operator, so "passing arguments to" cout doesn't really work the same way as a function. I put that in quotations because you are not passing arguments at all and it's not even a function. cout is an object with an operator overload defined for the << operator.
When you have something like cout << a | b; you end up with (cout << a) | b due to Operator Precedence. The cout << a part is valid because cout has an overload for <<, so that part returns a reference to cout, and you end up doing cout | b, but cout has no overload for the | operator, so you get a compilation error.
because operator precedence
cout<<a|b becomes (cout<<a)|b
while
cout<<a+b becomes cout<<(a+b)
When parsing an expression, an operator which is listed on some row of the operator precedence table will be bound tighter (as if by parentheses) to its arguments than any operator that is listed on a row further below it with a lower precedence.
For example, the expression std::cout << a | b is parsed as (std::cout << a) | b, and not as std::cout << (a | b).
So in your example:
cout<<(a|b) works as intended because of parentheses but cout<<a|b will not.
But in the case of cout<<a+b, + has a greater precedence than << and it works even without the parentheses as a+b is evaluated first.
So cout<<a+b is the same as cout<<(a+b).

Postfix and prefix increment that causes an error

Why does that code does not compile due to an error:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout << ++(i++) << " " << i << endl;
return 0;
}
While that code does compile:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout << (++i)++ << " " << i << endl;
return 0;
}
I do not understand that. From my point of view it would be pretty reasonable for the first chunk to compile. The expression ++(i++) would just mean take i, increment it and output, then increment it again.
I am not asking about an undefined behavior in int overflow. I do not know about r and l value at all at the time of writing the question and I do not care why is ++i considered an l-value, but i++ is not.
This is because the post increment and pre increment operators return values with different types. Result of post increment is a so-called 'rvalue', meaning it can not be modified. But pre-increment needs a modifiable value to increment it!
On the other hand, result of pre-increment is an lvalue, meaning that it can be safely modified by the post increment.
And the reason for above rules is the fact that post-increment needs to return a value of the object as it was before increment was applied. By the way, this is why in general case post-incrememts are considered to be more expensive than pre-increments when used on non-builtin objects.
Shortly speaking the difference is that in C++ you may use any even number of pluses (restricted only by the compiler limits) for the prefix increment operator like this
++++++++++++++++i;
and only two pluses for the post increment operator
i++;
The postfix increment operator returns a value (The C++ Standard, 5.2.6 Increment and decrement)
1 The value of a postfix ++ expression is the value of its
operand. [ Note: the value obtained is a copy of the original value
—end note ]
While the prefix increment operator returns its operand after increment (The C++ Standard ,5.3.2 Increment and decrement)
1 ...The result is the updated operand; it is an lvalue...
Opposite to C++ in C you also can apply only two pluses to an object using the prefix increment operator.:) Thus the C compiler will issue an error for such an expression like this
++++++++++++++++i;
When you compile it with clang you get error message that says it all.
<source>:8:13: error: expression is not assignable
cout << ++(i++) << " " << i << endl;
Maybe it is good to start with ++ operator. In fact it is shorthand for i = i + 1. Now if we look at postfix version i++, it says in standard that it returns copy of original value and as side efect it increments original value.
So from (i++) you get rvalue and are trying to assign to it and as we know you can't assign to rvalue.

Is using an assignment operator in a function argument undefined behaviour?

I found some code similar to this in an example my university tutor wrote.
int main(){
int a=3;
int b=5;
std::vector<int>arr;
arr.push_back(a*=b);
std::cout<<arr[0]<<std::endl;
}
Is there a well-defined behaviour for this? Would arr[0] be 3 or 15 (or something else entirely)?
Visual Studio outputs 15, but I have no idea if that's how other compilers would respond to it.
Before push_back is executed, the expression passed as argument will need to be computed. So what is the value of a *= b. Well it will always be a * b and also the new value of a will be set to that one.
It's valid and works as you expect.
The expression is first evaluated and the result is "returned".
auto& temp = (a*=b);
arr.push_back(temp);
The value of an expression with the compound assignment operator is the value of the left operand after the assignment.
So the code your showed is valid. Moreover in C++ (opposite to C) the result is an lvalue. So you may even write :)
arr.push_back( ++( a *= b ) );
In this case the next statement outputs 16.:)

increment and addition operators precedence, cpp

I have 2 questions.
consider this code:
int x=1,y=2;
int z =(x++)+(++y);
int w = (++x)++;
cout << z << "\t" << w << "\t" << x;
Now, this gives me 4, 3 and 4 and I'm guessing that w=3is because this int w = (++x)++ is undefined behavior, and that's fine with me. What I don't understand is this: I tried to write this line int w = (++x)++; like this int w = ++x++; and got error: lvalue required as increment operand, but, I saw here that postfix takes precedence over prefix, so why the isn't the postfix increment done, returns the variable and then increments it with the prefix? (as it is done when I use bracket)
Now back to this line: int z =(x++)+(++y). I tried to write it like int z =x+++++y and that didn't work - same error. Then I tried int z =x+++(++y) and it was fine, so what I think happened is this:
x++
++y
addition
but if I'm correct, why the brackets were needed? this is the way it should be by precedence
so why the isn't the postfix increment done, returns the variable
The postfix version doesn't return a reference, it returns a value - and the prefix increment can only work with a reference.
By adding brackets, you've changed the order of evaluation.
It is not an issue of precedence, but the way compiler parses the code.
To compile correctly you don't need to use brackets. Will work fine with spaces.

Why doesn't *ptr++ change the value of the pointee, but (*ptr)++ does?

I was writing this program
int x = 10;
int *yptr;
yptr = &x;
cout << "The address yptr points to = " << yptr;
cout << "The contents yptr points to =" << *yptr ;
(*yptr)++ ;
cout << "After increment, the contents are: " << *yptr;
cout << "The value of x is = " << x ;
Value increased of x from 10 to 11.
But when I write
*yptr ++ ;
Value did not increase, why?
In C++ language the grouping between operators and their operands is defined by the grammar. For convenience, this grouping is often expressed in simplified linear form called operator precedence. In C++ postfix operators have higher precedence than prefix/unary ones. So, in your case *yptr++ stands for *(yptr++), since postfix ++ has higher precedence than unary *. The ++ operator is applied directly to yptr and * is applied to the result of yptr++.
When you added the extra (), you completely changed the expression and re-grouped the operators and operands. In (*yptr)++ you forcefully associated the * with yptr. Now, * operator is applied directly to yptr and ++ is applied to the result of *yptr. Hence the change in the behavior.
In other words, the answer to your "why?" question is: because you explicitly asked the compiler make that change. The original expression was equivalent to *(yptr++) and you changed it to (*yptr)++. These are two completely different expressions with completely different meanings.
P.S. Note that the sequencing rules of C++ language does not generally allow one to describe the behavior of built-in operators in therms of what is evaluated "first" and want is evaluated "next". It is tempting to describe behavior of these expressions in therms of "++ works first, * works next", but in general case such description are incorrect and will only lead to further confusion down the road.
When you write (*yptr)++ first (*yptr) is fetched because () has higher precedence than ++, which is 10 and then ++ operator is applied, resulting 11. When you write *y ++;, first y++ is evaluated as ++ has higher precedence. That means the address is increased, then the content is fetched for * operator instead of incrementing the content. Learn operator precedence
(*ptr)++ increment the value that saved into ptr.
Like this
int *ptr;
*ptr =1;
(*ptr)++;
std::cout<< *ptr; //out put will be 2
BUT
*ptr++ increment the address of the usually for char pointer variables.
Like this
char *ptr = "Hello";
while(*ptr++)
std::cout<<*ptr; //out put will be ello