By reading the book "C++ Primer" and wikipedia, I notice both mentioned that "precedence and associativity defines the grouping of OPERATORS". However, it appears to me the examples they given were showing grouping of OPERANDS. Here I quote:
from "Defined terms # C++ Primer 5th edition":
associativity: Determines how OPERATORS with the same precedence are
grouped.
from Operator_associativity # Wikipedia:
Consider the expression a ~ b ~ c. If the operator ~ has left
associativity, this expression would be interpreted as (a ~ b) ~ c. If
the operator has right associativity, the expression would be
interpreted as a ~ (b ~ c).
But from what I see, the above explanation grouped two OPERANDS (not operators): a and b into (a ~ b), or b and c into (b ~ c). Because I see they parenthesized two operands, but not two operators.
Given that operator and operands are different concepts, does the precedence and associativity rule group operator or operands ?
Thanks in advance.
Precedence and associativity address how a language interprets parenthesis-free expressions involving three or more operands. I'll use the symbols # and # to denote two operators. Consider the expressions
a # b # c,
x # y # z,
d # e # f, and
u # v # w.
Note that the first two expressions involve different operands. The C++ precedence rules determines whether a#b#c is interpreted as meaning (a#b)#c or a#(b#c), and whether x#y#z is interpreted as meaning x#(y#z) or (x#y)#z.
The latter two expressions involve the same operand. Precedence has no bearing here. It's associativity that determines whether d#e#f is interpreted as meaning (d#e)#f or d#(e#f), and whether u#v#w is interpreted as meaning (u#v)#w or u#(v#w).
C++ has a large number of operators. There's an easy way to deal with the plethora of precedences: Use parentheses. My rule is "Everyone knows a*b+c means (a*b)+c. Nobody but a language lawyer knows whether a?b:c=d means (a?b:c)=d or a?b:(c=d). Use parentheses when in doubt."
Note: Apparently even Microsoft and wikipedia don't know the correct answer to "What does a?b:c=d mean?", at least as of June 16, 2014. The precedence tables at wikipedia and Microsoft have the ternary operator separate from the lower precedence assignment operators, which is incorrect. That would mean a?b:c=d needs to be interpreted as (a?b:c)=d, which always assigns the value of d to b or c, depending on whether a is true of false. That is incorrect. The correct interpretation is a?b:(c=d). The precedence tables at cppreference.com and cplusplus.com correctly group the ternary operator with the assignment operators.
There's an even better solution to puzzling out what the standard says: Just use parentheses.
Given that operator and operands are different concepts, does the precedence and associativity rule group operator or operands ?
Both. It groups operands and the corresponding operator(s). In:
(a ~ b) ~ c
you are grouping a and b, which are operands, by the ~ operator. Precedence and associativity are properties only of the operand, though.
The associativity rules of a language specify which operator is evaluated first when two operators with the same precedence are adjacent in an expression.
The precedence rules of a language specify which operator is evaluated first when two operators with different precedence are adjacent in an expression.
Wiki says:
[..] the associativity (or fixity) of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses. If an operand is both preceded and followed by operators (for example, "^ 4 ^"), and those operators have equal precedence, then the operand may be used as input to two different operations (i.e. the two operations indicated by the two operators). The choice of which operations to apply the operand to, is determined by the "associativity" of the operators.
This means that operators are grouped among the operands and operands are grouped among the operators.
Related
The operator '&' can be used in both of following way int a; scanf("%d",&a);
and printf("%d",1&2).
But different behaviour (for first as address operator and second time as bit-wise operator).
I know operator overloading is not there in C. Then how it works ?. Also highlight for c++.
I know operator overloading is not there in C.
This is incorrect. a + b performs integer addition if a and b are integers, floating-point addition of a and b are floating-point numbers, and pointer arithmetic if a or b is a pointer.
C has operator overloading built into the language. It does not support custom operator overloading defined by the program.
In the case of & being an operator for taking an address and for performing a bitwise AND, the distinction is made by the language grammar. The & for taking an address can appear only applied to a cast-expression in the grammar. The & for bitwise AND can appear only after an AND-expression and before an equality-expression. These “tokens” (cast-expression, AND-expression, and equality-expression) may be unfamiliar to you, but they are formally defined in the grammar for the C language, and, as the compiler is parsing source code, it recognizes the structure of expressions and matches the source code to the tokens of the grammar. This is also true for C++ except for a minor technical difference: In C++, one of the tokens is and-expression instead of AND-expression.
The definition of the grammar is such that recognition of these tokens always uniquely distinguishes how the & operator is being used.
In "C" language, operators have different meaning when they are used as prefix to expression, suffix to expression or "infix" (between two expressions).
Consider '*', which performs multiplication as 'infix' operator, and pointer indirection when used as a prefix. Similarily, the '-' operator, which performs subtraction as 'infix' operator, and negation when used as a prefix.
Basically, it's not about overriding, it if the operator appears between two expressions, or as a prefix to a single expression.
In the same way, The "C" compiler knows if the '&' is bit-wise and, or address-of, based on it's position is the expression: If it is between two expressions, it's the AND, if it is before an expression, it is 'address-of'.
See https://en.wikipedia.org/wiki/Infix_notation about infix.
C does not support operator overloading (beyond what it built into the language).
As you can see in this Wikipedia Operators in C
The Address-of ("address of a") "&a" is defined as R* K::operator &();
whereas
The Bitwise AND "a & b" is defined as R K::operator &(S b);
So basically the "&" operator has different meaning when used as a unary operator and as a binary operator operator. The same goes for various other operators like, "*" , "-", etc.
It has simple different meanings when applied to the lvalue (it the unary operator in this case) or when it is used in the math expression with two operands.
"The operator & can be used in both of following way int a; scanf("%d",&a); and printf("%d",1&2)."
Note that in the case of C++ you forgot another important third use. The & operator can also be used to declare references.
int x = 24;
int& r_x = x;
the language divides operators based on its operands first. In one category itself overloading can be in-built. Your example is about the first division. Address-of is a unary operator and bitwise-AND is a binary operator. when you write operator function in c++ you will see the difference of these two categories.
Operator overloading is inbuilt to languages. example simple arithmetic addition operator. it can work with simple one-byte integer data as well as float (significant & exponent). Basically it is there with maths. so while making C language, they just translated those into functionality. In C specification, you cannot find overloading as a keyword for this behavior. According to them, after formula expression, anything has to be expressed as different functions. Each function should be named based on the functionality that it offers. When C++ introduced an opportunity to create new types, operators with its basic n-nary form allowed to operate with new types. In a nutshell, C's philosophy was different.
This question already has answers here:
Operator Precedence vs Order of Evaluation
(6 answers)
Closed 5 years ago.
Grouping operators and operands and Order of Evaluation are two important concepts of expression in C++.
Grouping
For expression with multiple operators, how the operands grouped with the specific operators is decided by the precedence and associativity of the operators and may depend on the order of evaluation.
Order
In C++, only 4 operators have the specified order of evaluations (logical AND, logical OR, conditional and comma operator). For the other operators, the evaluation order is unspecified.
Parentheses
Parentheses can override the precedence and associativity, and therefore specify the grouping of a compound expression.
However, the book by Peter Gottschling claims the parentheses can change the order of the evaluation. I personally doubt it; I think it's an error! In the example from the quotation below, the parentheses do not tell which expression of x, y and z is evaluated first, which one is later and which one is the last. It only groups the expression y + z as the left operand of the * operator.
An expression surrounded by parentheses is an expression as well,
e.g., (x + y). As this grouping by parentheses precedes all operators,
we can change the order of evaluation to suit our needs: x * (y + z)
computes the addition first. Discovering Modern C++, Chapter 1.4.1
Question
Can parentheses override expressions' order of evaluation?
The quoted sentence is poorly worded. The author didn't mean that the order of evaluation is changed, or even specified; I think the word "order" was meant in terms of how a human might read the expression (i.e. precedence).
Of course, if the three variables are independent and reading them has no side-effects, the "as if" rule makes the unspecified order irrelevant, as it wouldn't change the value of the expression.
I came across the following when learning C++
int a = 5;
-----a;
The second statement doesn't compile. The statement could either be read as --(--(-a)) or -(--(--a)), since both operators are in the same precedence group. In this case though only the second interpretation (when you DO use brackets) makes sense. Therefore I see no ambiguity.
My question therefore is: why is the unary negation not in a higher precedence group than the prefix decrement?
Are operator precedence & associativity rules ever violated in any C/C++ expression?
If so, can you give an example?
Assume the claims of precedence and associativity rules are:
Each operator has a given precedence level, and each precedence level has a given associativity. If a sub-expression is seen by two operators where they expect an operand, it belongs to the one with higher precedence. Ties are broken by associativity.
Edit: Background
The standard defines C/C++ expressions as a CFG, which is much more flexible than a precedence-based parser. For example, it would have been possible to give binary operators asymmetrical "precedence", which would have rendered any precedence table incorrect. However, it appears to me that the design of the grammar was constrained to uphold simple precedence rules. Here are some alleged "counterexamples" that I have come across:
1) a?b,c:d is not interpreted as (a?b),(c:d)
Some claim that the ?: operator exhibits different precedence towards its middle operand than towards its other operands, because a?b,c:d, for example, is not interpreted as (a?b),(c:d). However, neither b nor c occupies a position in which it appears to ?: as its inner operand. By that reasoning a[b+c] should be interpreted as (a[b)+(c]), which is ludicrous.
2) sizeof(int)*a is interpreted as (sizeof(int))*a rather than sizeof((int)(*a))
... because C disallows an uparenthesized cast as sizeof's operator. However, both of these interpretations conform to precedence rules. The confusion comes from the * operator's ambiguity (Is it the binary or the unary operator?). Precedence tables are not meant to resolve operator ambiguities. They are, after all, not operator-symbol-precedence tables. So the operator precedence rules themselves are intact.
3) a+b=c results in syntax error, not semantic error
a+b=c, according to the standard, is invalid C syntax. If C had had a precedence-based parser, it would only have been caught at the semantic level. In C, it so happens that any expression that is not a unary-expression cannot be l-valued. These semantically doomed LHS expressions therefore do not need to be accommodated syntactically. It makes no difference to the language as a whole, and precedence tables needn't be in the business of predicting the syntacticness/symanticness of the error that is going to result from an expression.
For one example, the usual precedence table says that sizeof and cast expressions have the same precedence. Both the table and the standard say that they associate right-to-left.
This simplification is fine when you're looking at, say, *&foo, which means the same as *(&foo).
It might also suggest to you that sizeof (int) 1 is legal C++ and that it means the same thing as sizeof( (int) 1 ). But it's not legal, because in fact sizeof( type-id ) is a special thing of its own in the grammar. Its existence prevents sizeof (int) 1 from being a sizeof expression whose operand is a cast-expression whose operand is 1.
So I think you could say that the "sizeof ( type-id )" production in the C++ grammar is an exception to what the usual precedence/associativity tables say. They do accurately describe the "sizeof unary-expression" production.
It depends on whether the "rules" are correct. The language definition doesn't talk about precedence, so the precedence tables you see in various places may or may not reflect what the language definition actually requires.
Until someone can find a counterexample, I'm going to put forward this as the default answer:
No, C/C++ precedence and associativity rules are never violated.
Let me present a example :
a = ++a;
The above statement is said to have undefined behaviors ( I already read the article on UB on SO)
but according precedence rule operator prefix ++ has higher precedence than assignment operator =
so a should be incremented first then assigned back to a. so every evaluation is known, so why it is UB ?
The important thing to understand here is that operators can produce values and can also have side effects.
For example ++a produces (evaluates to) a + 1, but it also has the side effect of incrementing a. The same goes for a = 5 (evaluates to 5, also sets the value of a to 5).
So what you have here is two side effects which change the value of a, both happening between sequence points (the visible semicolon and the end of the previous statement).
It does not matter that due to operator precedence the order in which the two operators are evaluated is well-defined, because the order in which their side effects are processed is still undefined.
Hence the UB.
Precedence is a consequence of the grammar rules for parsing expressions. The fact that ++ has higher precedence than = only means that ++ binds to its operand "tighter" than =. In fact, in your example, there is only one way to parse the expression because of the order in which the operators appear. In an example such as a = b++ the grammar rules or precedence guarantee that this means the same as a = (b++) and not (a = b)++.
Precedence has very little to do with the order of evaluation of expression or the order in which the side-effects of expressions are applied. (Obviously, if an operator operates on another expression according to the grammar rules - or precedence - then the value of that expression has to be calculated before the operator can be applied but most independent sub-expressions can be calculated in any order and side-effects also processed in any order.)
why it is UB ?
Because it is an attempt to change the variable a two times before one sequence point:
++a
operator=
Sequence point evaluation #6: At the end of an initializer; for example, after the evaluation of 5 in the declaration int a = 5;. from Wikipedia.
You're trying to change the same variable, a, twice. ++a changes it, and assignment (=) changes it. But the sequence point isn't complete until the end of the assignment. So, while it makes complete sense to us - it's not guaranteed by the standard to give the right behavior as the standard says not to change something more than once in a sequence point (to put it simply).
It's kind of subtle, but it could be interpreted as one of the following (and the compiler doesn't know which:
a=(a+1);a++;
a++;a=a;
This is because of some ambiguity in the grammar.