Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operator precedence in the given expressions

Expression 1: *p++; where p is a pointer to integer.

p will be incremented first and then the value to which it is pointing to is taken due to associativity(right to left). Is it right?

Expression 2: a=*p++; where p is a pointer to integer.

Value of p is taken first and then assigned to a first then p is incremented due to post increment. Is it right?

like image 635
Vipul Prakash Avatar asked May 25 '17 09:05

Vipul Prakash


People also ask

What is the precedence of operators in an expression?

The precedence of operators determines which operator is executed first if there is more than one operator in an expression. Let us consider an example: int x = 5 - 17* 6; In C, the precedence of * is higher than - and = . Hence, 17 * 6 is evaluated first.

What is the priority among (* %) (+ -) and (=) C operators?

1) What is the Priority among (*, /, %), (+, -) and (=) C Operators.? Explanation: Assignment operator in C has the least priority.

What is the order of precedence of operations?

It stands for Parentheses, Exponents, Multiplication/Division, Addition/Subtraction. PEMDAS is often expanded to the mnemonic "Please Excuse My Dear Aunt Sally" in schools.


5 Answers

Associativity is not relevant here. Associativity only matters when you have adjacent operators with the same precedence. But in this case, ++ has higher precedence than *, so only precedence matters. Because of precedence, the expression is equivalent to:

*(p++)

Since it uses post-increment, p++ increments the pointer, but the expression returns the value of the pointer before it was incremented. The indirection then uses that original pointer to fetch the value. It's effectively equivalent to:

int *temp = p;
p = p + 1;
*temp;

The second expression is the same, except it assigns the value to another variable, so that last statement becomes:

a = *temp;
like image 159
Barmar Avatar answered Oct 07 '22 09:10

Barmar


First of all, let me tell you that, neither associativity nor order of evaluation is actually relevant here. It is all about the operator precedence. Let's see the definitions first. (emphasis mine)

  • Precedence : In mathematics and computer programming, the order of operations (or operator precedence) is a collection of rules that reflect conventions about which procedures to perform first in order to evaluate a given mathematical expression.

  • Associativity: In programming languages, 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.

  • Order of evaluation : Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified, except a few cases. There's mainly two types of evaluation: a) value computation b) side effect.


Post-increment has higher precedence, so it will be evaluated first.

Now, it so happens that the value increment is a side effect of the operation which is sequenced after the " value computation". So, the value computation result, will be the unchanged value of the operand p (which again, here, gets dereferenced due to use of * operator) and then, the increment takes place.

Quoting C11, chapter §6.5.2.4,

The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand. [.....]

The order of evaluation in both the cases are same, the only difference is, in the first case, the final value is discarded.

If you use the first expression "as-is", your compiler should produce a warning about unused value.

like image 21
Sourav Ghosh Avatar answered Oct 07 '22 08:10

Sourav Ghosh


Postfix operators have higher priorities than unary operators.

Thus this expression

*p++

is equivalent to the expression

*( p++ )

According to the C Standard (6.5.2.4 Postfix increment and decrement operators)

2 The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand.

So p++ yields the original value of the pointer p as the result of the operation and has also a side effect of incrementing the operand itself.

As for the unary operator then (6.5.3.2 Address and indirection operators)

4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined

So the final result of the expression

*( p++ )

is the value of the object pointed to by the pointer p that also is incremented due to the side effect. This value is assigned to the variable a in the statement

a=*p++;

For example if there are the following declarations

char s[] = "Hello";
char *p = s;
char a;

then after this statement

a = *p++;

the object a will have the character 'H' and the pointer p will point to the second character of the array s that is to the character 'e'.

like image 26
Vlad from Moscow Avatar answered Oct 07 '22 10:10

Vlad from Moscow


The expression

*p++

is equivalent to

*(p++)

This is due to precedende (i.e.: the postfix increment operator has higher precedence than the indirection operator)

and the expression

a=*p++

is for the same reason equivalent to

a=*(p++)

In both cases, the expression p++ is evaluated to p.

like image 36
ネロク・ゴ Avatar answered Oct 07 '22 10:10

ネロク・ゴ


  • v = i++;: i is returned to the equality operation and then assigned to v. Subsequently, i is incremented (EDIT: technically it's not necessarily executed in this order). Thus v has the old value of i. I remember it like this: ++ is written last and therefore happens last.
  • v = ++i;: i is incremented, and then returned to be assigned to v. v and i has the same value.
  • When you don't use the returned value, they do the same (although different implementations may yield different performance in some cases). E.g. in for loops, for(int i=0; i<n; i++) is the same as for(int i=0; i<n; ++i). The latter is sometimes automatically preferred because it tends to be faster for some objects.
  • * has lower precedence than ++ so *p++ is the same as *(p++). Thus in this case p is returned to * which dereferences it. Then the address in p is incremented by one element. *++p increments the adress of p first, then dereferences it.
  • v = (*p)++; sets v equal to the old value pointed to by p and then increments it, while v = ++(*p); increments the value pointed to by p and then sets v equal to it. The address in p is unchanged.

Example: If,

int a[] = {1,2};

then

int v = *a++;

and

int v = *++a;

will both leave a incremented, but in the first case v will be 1 and in the latter it'll be 2.

like image 23
sigvaldm Avatar answered Oct 07 '22 08:10

sigvaldm