Hello guys after going through href=http://en.cppreference.com/w/c/language/operator_precedence this link ,
I thought I understood the operator precedence but I came to followings doubt.
The link says that When parsing an expression, an operator which is listed on some row will be bound tighter (as if by parentheses) to its arguments than any operator that is listed on a row further below it. For example, the expression *p++ is parsed as *(p++), and not as (*p)++.
So how does the expression ++*p gets evaluated is it like ++(*p) but if yes ++ has higher priority or bound then *, Then why does * is bound tighter in the above case, and what about the expression *++p ?
Operator precedence defines which operator should be applied first when there is more than one choice.
From your link:
Precedence and associativity are independent from order of evaluation.
The expression ++*p, or any expression of the form:
{operator 2} {operator 1} {expression}
has a well-defined order of evaluation, where {operator 1} {expression} must be applied in order to make an expression that {operator 2} may act on.
Yes ++ has higher precedence over * and the associativity for both is from right to left.
So
++*p will be evaluated as ++(*p) because ++ need to be applied on a modifiable value.
Whereas
*++p as you see when this is evaluated the operator close to p is ++ as well as have higher precedence over * so ++p will happen first followed by dereferencing *(++p)
Related
We know ++ and - - can be prefix or postfix and it depends on the position of the operand. for example :
++a prefix because the operand is on the right of the operator.
a++ postfix because the operand is on the left of the operator.
But In complicated expressions things become confusing. for example :
! - -a == ++ ! b I know to solve this i must apply the precedence rule but that depend on how i will consider the type of ++ , a postfix or prefix.
My question how can i decide if an operator a postfix or a prefix and more generaly how can i determine the operand of an unary operator ?
Don't.
Making some assumptions about type, your code should be:
!(-(-a)) == ++(!b)
Note the use of parentheses to obviate the need to even think about precedence.
Except this isn't a valid expression, because you can't increment an rvalue/temporary (assuming you aren't overloading operator! and returning a reference, which would be non-idiomatic and weird).
Also each side of the == should be split off into a variable declaration for clarity.
const bool isItHot = !a;
const bool isItCold = !b; // ignoring your ++ for now
return (isItHot == isItCold);
If you really need a tool to work out the precedence for you, Geordi can do it, or you can work it out from some documentation.
Whilst looking up operator associativity on wikipedia, I noticed that delete has an associativity of right to left. The source is cited as msdn, I checked it and it comes under group 3 precedence, right to left associativity. So I checked the C++ standard (n4296)
5.3 Unary expressions [expr.unary]
1) Expressions with unary operators group right-to-left
unary-expression:
postfix-expression
++ cast-expression
-- cast-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
sizeof ... ( identifier )
alignof ( type-id )
noexcept-expression
new-expression
delete-expression
unary-operator: one of
* & + - ! ~
What implications does this have? What does delete have any associativity at all?
As Barry said, precedence is determined by the grammar (and there are a few operators that don't really fit well with the basic idea of precedence so you can only really figure out what happens entirely correctly from the grammar, not a precedence table).
Even if we ignore that, however, the precedence of delete only (at least usually) determines whether a statement is legal/allowed, not what it means. To give a counterexample, with + and *, precedence determines that 2 * 3 + 4 yields 10 rather than 14 (i.e., multiplication takes precedence).
In the case of delete, no value is produced as a result of the delete statement, so a statement like delete x + y; simply isn't allowed. It would be parsed as (delete x) + y;, but since delete x doesn't produce a value that can be added to anything else, the result is always prohibited (and if you change the operator, that will remain true).
Associativity doesn't really make sense for delete. In particular, associativity deals with whether something like: a # b # c will be parsed as (a # b) # c or a # (b # c) (where # is some operator). That's only really meaningful for operators that take two operands though. There's simply no way to combine deletes in a way that allows you to ask the question(s) that associativity answers.
The C++ standard typically does not define operators in terms of precedence or associativity. It defines them in terms of grammar. From [expr.delete], delete is used in a delete-expression which is defined as:
delete-expression:
::opt delete cast-expression
::opt delete [] cast-expression
Where cast-expression is defined in [expr.cast]:
cast-expression:
unary-expression
( type-id ) cast-expression
And unary-expression is a whole bunch of things defined [expr.unary], that are all unary expressions (increments, decrements, deletes themselves)
That is, delete *x is right to-left associative because (delete (*x)) is the only way to parse that expression according to the grammar.
This is also reason that cppreference cites delete's precedence where it does is a direct consequence of that. For example, delete is higher than + because in an expression like this:
delete x+y
x+y is not a unary-expression, so the only legitimate parsing of the grammar would be (delete x) + y.
Associativity is about whether a op b op c is parsed as (a op b) op c or a op (b op c).
delete is a unary operator, so it cannot associate. It has no associativity.
And delete delete x is never valid.
Consider the following codes:
int a = 3;
int b = 0;
b = a > 0 ? ++b, ++a : --a, b = 0;
After execution, I get the value of b to become 0 and the value of a to become 4.
That means the result of condition expression, a > 0 is evaluated as true and the expression a++ has been executed, while the expression b = 0 after , hast been executed ,too. In other words, the expression b = 0 is not an operand of the ternary operator, while ++b is. Otherwise, b = 0 won't be executed since the condition expression isn't evaluated as false.
My question is "according to what rule does the compiler kick b = 0 out of the ternary operator's operand?"
The operators in the third statement includes: ++ and --, which have the highest precedence, >, which has the second largest precedence, ? : and =, which have the third largest precedence and , with the lowest precedence. I know that operators with higher precedence should determine their operands earlier so that ++,--, and > are handled first. Then the statement is equivalently:
b = (a > 0) ? (++b), (++a) : (--a), b = 0;
Now, it's = and ?:'s turn to be handled. The associativity of = and ?: is right-to-left, so I consider the compiler will parse the statement from the right end.The first operator met is = and so b = 0 is grouped together. The second met operator is ,. Since it's precedence is lower then the current operators being analyzed, I assume the compiler will just skip it. Then the compiler met :, which is a part of ternary operator, so it keeps parsing.(Actually I don't know how the compiler can know that : is a part of ?: before parsing the whole ternary operator) Problem comes here. The next operator met by the compiler is , but the compiler haven't finished determining the operands of ?: yet. The , has lower priority than ?:. Theoretically it should be skipped; surprisingly, in practical test, the (++b) and (++a) have been concatenated by the , operator at this time and both are considered as the operand of ?:. That makes me confused. Why does the last , is ignored and doesn't included in the operand of ?: while the previous , in statement is kept in the operand of ternary operator?
May someone clarify the concepts of precedence and associativity with this example? I'm really confused about the executing result when first taking a sight of this piece of codes. I had thought that the expression b=0 is also a part of the ternary operator's operand; therefore b = 0 will only be executed if a > 0 is false.
Thanks in advance.
Precedence and associativity are different concepts, but technically the C and C++ standard specifies none. Instead they give the grammar rules to deduce the structure of the expression.
The relevant rules are:
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
expression:
assignment-expression
expression , assignment-expression
primary-expression:
( expression )
postfix-expression:
primary-expression
...
And so on...
The idea is that each type of expression can generate a composite expresion or another type of expression of lower precedence. You can only go up to the root expression by using parenthesis.
With that in mind, note that the conditional-expression that uses the ?: actually has different types of expressions in each of the three subexpressions. The middle one is expression so it will accept any kind of expression, even with , or = (no ambiguity here because of the ending :).
But note that the last one is assignment-expression, that is any kind of expression except the one with ,. If you want to use that, you will have to enclose it with () creating a primary-expression instead.
Bonus explanation: the first expression is logical-or-expression, and if you look carefully to the grammar you'll see that it excludes assignment operators, the conditional operator and the comma operator.
So your expression:
b = a > 0 ? ++b, ++a : --a, b = 0
Is actually a expression comma assignment-expression, where the first expression is b = a > 0 ? ++b, ++a : --a and the second assignment-expression is b = 0.
And so on...
Your expression is evaluated as (b = ((a > 0) ? (++b, ++a) : (--a))), (b = 0);.
As you say the ?: has higher precedence than the comma operator, so the b=0 does not belong to the ternary conditional. The difference for the left and the right part of the ternary operator is, that on the left side the compiler tries to evaluate the complete string ++b, ++a as an expression (knowing that the part between ? and : must be an expression, while on the right side the compiler tries to parse an expression as far as it can. And precedence of operators says the compiler must stop at the ,. On the left side the compiler does not stop on the , because this is a legal part of the expression.
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.
I know this is silly question but I don't know which step I'm missing to count so can't understand why the output is that of this code.
int i=2;
int c;
c = 2 * - ++ i << 1;
cout<< c;
I have trouble to understanding this line in this code:
c = 2 * - ++ i <<1;
I'm getting result -12. But I'm unable to get it how is precedence of operator is working here?
Have a look at the C++ Operator Precedence table.
The ++i is being evaluated, yielding 3.
The unary - is being evaluated, yielding -3.
The multiplication is being done1, yielding -6.
The bit shift is evaluated (shifting left by 1 is effectively multiplying by two) yielding -12.
The result -12 is being assigned to the variable c.
If you used parentheses to see what operator precedence was doing, you'd get
c = ((2 * (-(++i))) << 1);
Plus that expression is a bit misleading due to the weird spacing between operators. It would be better to write it c = 2 * -++i << 1;
1 Note that this is not the unary *, which dereferences a pointer. This is the multiplication operator, which is a binary operator.
Operator precedence defined the grouping between the operators and their operands. In your example the grouping is as follows
c = ((2 * (-(++i))) << 1);
That's how "precedence of operator is working here" and that's the only thing it does.
The result of this expression is -6 shifted one bit to the left. This happens to be -12 on your platform.
According to your comment in another answer, you mistakenly believe that operator precedence somehow controls what is executed "first" and what is executed "next". This is totally incorrect. Operator precedence has absolutely nothing to do with the order of execution. The only thing operator precedence does, once again, is define the grouping between the operators and their operands. No more, no less.
The order of execution is a totally different thing entirely independent from operator precedence. In fact, C++ language does not define any "order of execution" for expressions containing no sequence points inside (the above one included).