Probably been answered, but could not find it.
In c++ what does
if(a=b)
mean?
versus
if(a==b)
I just spent two hours debugging to find that
if(a=b)
compiles as
a=b
Why does compiler not flag
if(a=b)
as an error?
In c++ what does if(a=b) mean?
a=b is an assignment expression. If the type of a is primitive, or if the assignment operator is generated by the compiler, then the effect of such assignment is that the value of a is modified to match b. Result of the assignment will be lvalue referring to a.
If the operator is user defined, then it can technically have any behaviour, but it is conventional to conform to the expectations by doing similar modification and return of the left operand.
The returned value is converted to bool which affects whether the following statement is executed.
versus
if(a==b)
a==b is an equality comparison expression. Nothing is assigned. If the types are primitive, or if the comparison operator is generated by the compiler, then the result will be true when the operands are equal and otherwise false.
If the operator is user defined, then it can technically have any behaviour, but it is conventional to conform to the expectations by doing similar equality comparison.
Why does compiler not flag
if(a=b)
as an error?
Because it is a well-formed expression (fragment) as long as a is assignable with b.
if(a=b) is a conventional pattern to express the operation of setting value of a variable, and having conditional behaviour depending on the new value.
Some compilers do optionally "flag" it with a warning.
Note that if you would assign value int a = 1 and you make an if statement
if (a = 2)
{
std::cout << "Hello World!" << std::endl;
}
It still works, even though they are two different values, they will do the std::cout
However if you use a double equals sign == it will not.
The reason for this is if you use the standard double equals sign == you are asking the code if a is equivalent to 2, if it is 2. Obviously it's not, so it doesn't std::cout. But if you use an equals sign, you are changing the value a to 2, so it continues with the if statement.
And, to prove this, try taking away the int a = 1 from before the if statement and add an int before a in the if statement, it works.
Related
Here's my simple code:
int main()
{
int x = 5;
cout << (x++) << endl;
return 0;
}
the code above prints 5, not 6, even with the parenthesis, My thought is x = x + 1 be executed first before it is printed out? can anyone explain to me what's going on here? Thank you
edit: i definitely understand ++x guys, my question is about change operator precedence using ()
i definitely understand ++x guys, my question is about change operator precedence using ()
Operator precedence has nothing to do with this.
The misunderstanding probably isn't your fault: you've likely been mistaught. Your teacher(s) told you that an operand with a higher precedence, than some other operand, will be "executed first".
While this is a common explanation in schools, it is not true.
There are three things that can change the meaning of an expression in this sense:
Operator precedence
This is merely a set of rules that tell us, and tell the compiler, which operands go to which operator. Like, in 3 + 5 * 7, do we pass 3+5 to the multiplication operator, or do we pass 5*7 to the addition operator? It's about parsing.
Evaluation order
Each operand then needs to be evaluated to produce a value (e.g. 3+5 becomes 8, or 5*7 becomes 35). The rules on the order in which these evaluations happen are quite complicated in C++, more so than you might expect, but you usually don't have to worry about them unless you're doing crazy things in between sequence points (to borrow pre-C++11 parlance).
(This is the closest you'll get to a notion of "will be executed first".)
The meaning of the operator
This is where you're coming unstuck here. The meaning of the postfix increment operator x++ is "increment x, and evaluate to the old value". Period. Full stop.
It doesn't matter which operator precedence rules led to the expression x++ being evaluated (as opposed to some other interpretation of the symbols in your code): when it's evaluated, whenever it's evaluated, you get the old value for x.
The meaning of the prefix increment operator ++x, however, is "increment x, and evaluate to the new value", and that's the behaviour you want, so that's the code you should write.
Ultimately, what sequence of computer instructions actually produces this behaviour is completely up to the compiler, and can be surprising. You shouldn't worry about it, as long as the program's result is as specified in the standard.
So just forget about this "will be executed first" stuff; it's rubbish.
The expression (x++), with or without parentheses, evaluates to the previous value of x, and has the side-effect of increasing x.
If you want to see the effect of the increase then use the obscure
cout << (x++, x) << endl;
The value of x++ is the value of x before incrementing, no matter how many brackets you put. This has nothing to do with operator precendence, but this is just how post increment is defined.
edit: i definitely understand ++x guys, my question is about change operator precedence using ()
I already mentioned it, but to be clear: The value you see has little to do with operator precedence. With or without brackets ++ comes before <<. Even if this wasnt the case it would not change the value you get from x++. You could change order of the operators if you wrote
(cout << x)++ << endl;
but that would try to call ++ on the stream...
This is because x++ evaluates the value of x (5 in your case) and will increase its value after that....
what you are looking for is the pre-increment, also ++x
That is because, it is unrelated to operator precedence. The post-increment operator ++, as opposed to the pre-increment operator, increments its operand after its evaluation.
So what you see is normal and that behavior cannot be changed by introducing enclosing parenthesis around the variable. If you want the opposite to happen, then you should use the pre-increment operator like the following:
cout << ++x << endl;
Is it safe to shorten this usage of the ternary operator:
process_ptr(ptr ? ptr : default_ptr);
with the short-circuit:
process_ptr(ptr || default_ptr);
in C and C++? In other words, are we guaranteed to get either ptr or default_ptr back from the experssion, or is it perhaps allowed for the expression to result in an arbitrary "logical true" value, if the expression is logically true?
This is the kind of code you'd see all over Perl code, but I rarely see it in C/C++, that's the original basis of my question.
The second expression will evaluate to either 1 or 0.
Quoting the C11 standard draft:
6.5.14 Logical OR operator
The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.
So the two expressions are very different, since one of them yields a pointer, and the other one an integer.
Edit:
One of the comments claims that this answer is only valid for c, and #Lightness Races in Orbit is right.
There are also answers that are only correct for c++1, although the only difference with them is that c++ has type bool and then it evaluates this expression as bool instead of int. But apparently there is an important issue with overloading || operator in c++, which prvents short-citcuiting to apply for the object that overloads it.
So for c++ there are more things to consider, but since this question was tagged with both languages tags, then it's necessary to mention at least the differece.
The rule still applies when short-circuiting applies, i.e. the result of the evaluation of the expressions is either 1 or 0 for c and true or false for c++.
1 Like these answers: 1, 2
Concerning the Perl style, which usually is of type
do_someting || die("didn't work")
This would work in C++ also.
function_returning_bool(some) || std::cout << "Error!" << std::endl;
This is due to the || being a logical OR operator and causing the short-circuit in this case if the return value is true.
But using it instead of the ternary operator is impossible.
std::cout << ("asd" || "dsa");
This will result in 1 being output.
No. The result type is int (or bool in C++), and will be either 1 or 0 (true or false in C++).
operator|| for pointers returns a bool, so ptr || default_ptr will evaluate to true if either ptr or default_ptr are non-null.
I m a total newbie to a C++ world (and C too). And don't know all its details. But one thing really bothers me.
It is constructions like :
while (a=b) {...} .As I understand this magic works because assignment operator in C and C++ returns something.
So the questions: what does it return? Is this a documented thing?Does it work the same in C and C++. Low level details about assignment operator and its implementation in both C and C++ (if there is a difference) will be very appreciated!
I hope that this question won't be closed, because I can't find a comprehensive explanation and good material on this theme from the low level point of view all the more so.
For built-in types in C++ evaluating an assignment expression produces an lvalue that is the left hand side of the assignment expression. The assignment is sequenced before the result can be used, so when the result is converted to an rvalue you get the newly assigned value:
int a, b=5;
int &c = (a=b);
assert(&c==&a);
b=10;
assert(10==(a=b));
C is almost but not exactly the same. The result of an assignment expression in C is an rvalue the same as the value newly assigned to the left hand side of the assignment.
int *c = &(a=b); // not legal in C because you can only take the address of lvalues.
Usually if the result of an assignment is used at all it's used as an rvalue (e.g., a=b=c), so this difference between C++ and C largely goes unnoticed.
The assignment operator is defined (in C) as returning the value of the variable that was assigned to - i.e. the value of the expression (a=b) is the value of a after the expression has been evaluated.
It can be defined to be something different (of the same type) for user-defined operator overloads in C++, but I suspect most would consider this to be a very unpleasant use of operator overloading.
You can use this (non-boolean) value in a while (or an if, etc.) because of type conversion - using a value in a conditional context causes it to be implicitly converted to something which makes sense in a conditional context. In C++, this is bool, and you can define your own conversion (for your own type) by overloading operator bool(). In C, anything other than 0 is true.
To understand such expressions, you have to first understand that, positive integers are considered as 'true' and 0 is considered as false.
An assignment evaluates to the left hand side of the operator = as its value. So, while(a=b) { } would mean, while(1 /*true*/) if a after being assigned to b evaluates to non-zero. Else, it is considered as while(0 /*false*/)
Similarly, with the operator (a=b)?1:0 is the value of a after being assigned to b .. if it is non-zero then the value is taken as true and the statement following ? will be executed, or the statement following : is executed.
Assignments usually evaluate to the value at the left hand side of the operator = where as, logical operators(such as ==, && etc) evaluate to 1 or 0.
Note: with C++, it will depend upon if or not, a certain operator is overloaded.. and it will also depend upon the return type of the overloaded operator.
The assignment operators in C and C++ return the value of the variable being assigned to, i.e., their left operand. In your example of a = b, the value of this entire expression is the value that is assigned to a (which is the value of b converted into the type of a).
So you can say that the assignment operator "returns" the value of its left operand.
In C++ it's a little more complicated because you can overload the = operator with an actual user-defined function, and have it return something other than the value (and type) of the left operand.
If I have a C statement with the logical OR operator || :
if (isFoo() || isBar())
blah();
I know the compiler generated code will not execute isBar() if isFoo() returns true.
What about the bitwise OR operator | ?
if (isFoo() | isBar())
blah();
Likely this is sloppy writing, or if the writer requires isBar() and isFoo() to be both be executed because of those functions' side-effects, then they should express their intent more clearly. Or maybe I'm wrong and this is an acceptable C/C++ idiom.
Nevertheless, will a decent compiler actually generate a temporary variable to do the bitwise or'ing of the return values of isFoo() and isBar() when optimizations are turned on? Or will it instead convert the bitwise OR operation into a logical OR operation in order to allow short-circuit'ing of the boolean expression in order to prevent the calling of isBar()?
The compiler is free to optimize the "or'ing" however it wants, but the program must behave as if both function calls actually happen, and they could happen in either order. This actually bit me once when I naively changed a || to | because I needed both calls to happen, but forgot that the right-hand call could happen before the left-hand one and that the right-hand one depended on the results of the left-hand one...and the bug didn't show up until somebody decided to try compiling my code with pcc instead of gcc. So my advice is to be careful with stuff like this and write out what you mean clearly.
Finally, note that I said "as if both function calls actually happen", because in the case where the compiler can determine that a function has no side effects, it might optimize out the right-hand side if the left-hand side resulted in a nonzero value.
"Nevertheless, will a decent compiler actually generate a temporary
variable to do the bitwise or'ing of the return values of isFoo() and
isBar() when optimizations are turned on?"
Yes. Short circuiting does not apply to bitwise operators.
No, this is not a reasonable coding practice. Apart from ||'s short-circuit and ordering semantics, it performs a different operation than |.
|| yields 1 if either operand is non-zero, 0 if both are zero.
| yields the bitwise or of its operands.
As it happens, the truth value of the result is going to be the same (I realized this as I was typing this answer). But consider the corresponding && vs. & operators. This:
if (isFoo() && isBar())
will be true if and only if both functions return a non-zero value, but this:
if (isFoo() & isBar())
will be true if and only if the bitwise and of the results is non-zero. If isFoo() returns 1 and isBar() returns 2 (both true results), then isFoo & isBar() will be 0, or false.
Note that the is*() functions declared in <ctype.h> are only specified to return non-zero for true; they can and do return values other than 0 or 1.
If you really want to avoid the short-circuit behavior of ||, assign the results to temporaries:
bool is_foo = isFoo();
bool is_bar = isBar();
if (is_foo && is_bar) ...
We are talking straight C here so we must have something like
typedef int BOOL;
BOOL isFoo();
BOOL isBAr();
This is because ony C++ (and not C) has a boolean type.
Now when we evaluate isFoo() || isBar() the compiler knows that since we are using logical or if isFoo() returns true, the the whole statement will evaluate to true regardless of the value of isBar(), the compiler can therefore safely short circuit `isBar().
However when we evaluate isFoo() | isBar() we are effectively ORing two integers. The compiler has no way of knowing that isFoo() and isBar() can only return 0 or 1 and therefore will have to evaluate both expressions because even if isFoo() returns 1, the final result may be something different (like 3).
C++ does have a bool type and if isFoo() and isBar() return bools the compiler really does not have to evalueate isBar(). I am not an expert on the C++ specification but I imagine since bitwise operators do not make sense for bool types, the bools will be promoted to int and evaluated accordingly.
How are the below valid and invalid as shown and what do they mean. When would such a situation arise to write this piece of code.
++x = 5; // legal
--x = 5; // legal
x++ = 5; // illegal
x-- = 5; // illegal
The postfix (x++/x--) operators do not return an lvalue (a value you can assign into).
They return a temporary value which is a copy of the value of the variable before the change
The value is an rvalue, so you could write:
y = x++ and get the old value of x
Given that both operator=() and operator++() can be overloaded, it is impossible to say what the code does without knowing more about the type of thing the operators are being applied to.
Those all modify the value of x more than once between sequence points, and are therefore undefined behavior, which you should carefully avoid. I don't see where the distinction between "legal" and "illegal" comes in - since the behavior is legal, any behavior (including sending assorted email to the Secretary of State) is perfectly in accordance with the Standard.
Assuming that the question is about built-in ++ and -- operators, none of these statements are strictly legal.
The first two are well-formed, i.e. they merely compilable because the result of prefix increment is lvalue. The last two are ill-formed, since the result of postfix increment is not a rvalue, which is why you can't assign to it.
However, even the first two are not legal in a sense that they produce undefined behavior. It is illegal to modify the same object more than once without an intervening sequence point. (Note also, that compilers are allowed to refuse to compile well-formed code that produces undefined behavior, meaning that even the first pair might prove to be non-compilable).
++x and --x both give you back x (after it's been incremented/decremented). At that point you can do what you want with it, including assign it a new value.
x++ and x-- both give you back what x was (just before it was incremented/decremented). Altering this value makes no more sense than changing any ordinary function's return value:
obj->getValue() += 3; // pointless
Frankly, you should never write that. Postincrement and pre-increment (and decrements) should only ever be used on their own. They're just recipes for confusion.
The only place I can think of where such a situation would occur is with an operator overload of operator++ and operator=. Even then, the definition isn't clear. What you code is saying basically is add one to x, then assign 5 to it. A question would arise such as why would you need to increment x before assigning 5 to it? The only possible explanation is if you have some sort of class where the ++ operator somehow increment an internal counter, then the assignment. No idea why such a thing is needed though.