I'm only a casual user of C, when programming for micros like Arduino, but I'm interested in bettering my understanding of the vernacular.
I know that you can shorthand things like x = x % 10 to x %= 10, and x = x + 1 to x += 1. But I couldn't wrap my head around compounding both parts of this:
x = (x + 1) % 10
If that's possible, what does it look like?
(x += 1) %= 10 ? That seems... if not wrong, then confusing.
The expression (x += 1) %= 10 is not legal in C. The result of an assignment operator, whether = or one of the compound assignment operators, is not a lvalue. Loosely speaking, this means it can't appear on the left side of an assignment.
That statement would have to be broken up in two parts:
x += 1;
x %= 10;
As an aside, (x += 1) %= 10 is valid in C++.
Just try x += 1; x %= 10; as an alternative, it will work, but it is not equivalent to the first expression. You cannot wrap both in a single expression[1] as
x op= expression;
means
x = x op (expression); /* look at the parenthesis */
and that forces the evaluation of the expression first. The only case in which
x = (x op1 a) op2 b;
could be converted to an op-assign operation is if the operators are associative and the expression can be converted to:
x = x op1 (a op2 b);
(or if op2 has higher precedence than op1, which means the evaluation order is as above) and then
x op1= a op2 b;
would be possible.
Examples
x = x + a + b; ==> x += a + b; /* this implies a different order of evaluation */
x = x + a * b; ==> x += a * b;
x = x + a % b; ==> x += a % b; /* % has higher precedence than + */
Note [1]: well, you can, but using another operator, the , comma operator, you can convert it to x += 1, x %= 10;
Related
A friend asked me to explain the difference between operator precedence and order of evaluation in simple terms. This is how I explained it to them :-
Let's take an example -
int x;
int a = 2;
int b = 5;
int c = 6;
int d = 4;
x = a * b / (c + d);
Here, the final value of x will become 1. This is because first, the values of c and d will be added together (6+4), then the values of a and b will be multiplied together (2*5), and finally, the division will take place (10/10), resulting in the final value becoming 1, which is then assigned to x.
All of this is specified by operator precedence.
In this example, the parentheses force the addition to take place before the multiplication and the division, even though addition has a lower precedence.
Also, the multiplication is executed before the division, because multiplication and division have the same precedence, and both of them have the associativity of left-to-right.
Now comes the important part, i.e. the order of evaluation of this expression.
On one system, the order of evaluation may be like this -
/* Step 1 */ x = a * b / (c + d);
/* Step 2 */ x = a * 5 / (c + d);
/* Step 3 */ x = a * 5 / (c + 4);
/* Step 4 */ x = a * 5 / (6 + 4);
/* Step 5 */ x = a * 5 / 10;
/* Step 6 */ x = 2 * 5 / 10;
/* Step 7 */ x = 10 / 10;
/* Step 8 */ x = 1;
Note that in any step, it is always ensured that the operator precedence is maintained, i.e. even though b was replaced by 5 in Step 2, the multiplication did not take place until Step 7. So, even though the order of evaluation is different for different systems, the operator precedence is always maintained.
On another system, the order of evaluation may be like this -
/* Step 1 */ x = a * b / (c + d);
/* Step 2 */ x = a * b / (6 + d);
/* Step 3 */ x = a * b / (6 + 4);
/* Step 4 */ x = a * b / 10;
/* Step 5 */ x = 2 * b / 10;
/* Step 6 */ x = 2 * 5 / 10;
/* Step 7 */ x = 10 / 10;
/* Step 8 */ x = 1;
Again, the operator precedence is maintained.
In the above example, the entire behaviour is well-defined. One reason for this is that all of the variables are different.
In technical terms, the behaviour in this example is well-defined because there are no unsequenced modifications to any variable.
So, on any system, x will always get assigned the value 1 finally.
Now, let's change the above example to this :-
int x;
int y = 1;
x = ++y * y-- / (y + y++);
Here, the final value that gets assigned to x varies between systems, making the behaviour undefined.
On one system, the order of evaluation may be like this -
/* Step 1 */ x = ++y * y-- / (y + y++); // (y has value 1)
/* Step 2 */ x = ++y * y-- / (1 + y++); // (y still has value 1)
/* Step 3 */ x = ++y * 1 / (1 + y++); // (y now has value 0)
/* Step 4 */ x = 1 * 1 / (1 + y++); // (y now has value 1)
/* Step 5 */ x = 1 * 1 / (1 + 1); // (y now has value 2)
/* Step 6 */ x = 1 * 1 / 2;
/* Step 7 */ x = 1 / 2;
/* Step 8 */ x = 0;
Again, the operator precedence is maintained.
On another system, the order of evaluation may be like this -
/* Step 1 */ x = ++y * y-- / (y + y++); // (y has value 1)
/* Step 2 */ x = ++y * y-- / (y + 1); // (y now has value 2)
/* Step 3 */ x = ++y * 2 / (y + 1); // (y now has value 1)
/* Step 4 */ x = ++y * 2 / (1 + 1); // (y still has value 1)
/* Step 5 */ x = ++y * 2 / 2; // (y still has value 1)
/* Step 6 */ x = 2 * 2 / 2: // (y now has value 2)
/* Step 7 */ x = 4 / 2;
/* Step 8 */ x = 2;
Again, the operator precedence is maintained.
How can I improve this explanation?
I would prefer an explanation that uses function calls. A function call makes it very obvious that "something needs to be evaluated before applying the operator".
Basic example:
int x = a() + b() * c();
must be calculated as
temp = result_of_b_func_call * result_of_c_func_call
x = result_of_a_func_call + temp
due to multiplication having higher precedence than addition.
However, the evaluation order of the 3 function calls is unspecified, i.e. the functions can be called in any order. Like
a(), b(), c()
or
a(), c(), b()
or
b(), a(), c()
or
b(), c(), a()
or
c(), a(), b()
or
c(), b(), a()
Another basic example would be to explain operator associativity - like:
int x = a() + b() + c();
must be calculated as
temp = result_of_a_func_call + result_of_b_func_call
x = temp + result_of_c_func_call
due to left-to-right associativity of addition. But again the order of the 3 function calls are unknown.
If function calls is not an option, I would prefer something like
x = a * b + c / d
Here it's pretty obvious that there are two sub-expressions, i.e. a * b and c / d. Due to operator precedence both of these sub-expressions must be evaluated before the addition but the order of evaluation is unspecified, i.e. we can't tell whether the multiplication or the division is done first.
So it can be
temp1 = a * b
temp2 = c / d
x = temp1 + temp2
or it can be
temp2 = c / d
temp1 = a * b
x = temp1 + temp2
All we know is that the addition must be last.
6.5 Expressions
...
3 The grouping of operators and operands is indicated by the syntax.85) Except as specified
later, side effects and value computations of subexpressions are unsequenced.86)
85) The syntax specifies the precedence of operators in the evaluation of an expression, which is the same
as the order of the major subclauses of this subclause, highest precedence first. Thus, for example, the
expressions allowed as the operands of the binary + operator (6.5.6) are those expressions defined in
6.5.1 through 6.5.6. The exceptions are cast expressions (6.5.4) as operands of unary operators
(6.5.3), and an operand contained between any of the following pairs of operators: grouping
parentheses () (6.5.1), subscripting brackets [] (6.5.2.1), function-call parentheses () (6.5.2.2), and
the conditional operator ? : (6.5.15).
Within each major subclause, the operators have the same precedence. Left- or right-associativity is
indicated in each subclause by the syntax for the expressions discussed therein.
86) In an expression that is evaluated more than once during the execution of a program, unsequenced and
indeterminately sequenced evaluations of its subexpressions need not be performed consistently in
different evaluations.
C 2011 Online Draft
Precedence and associativity only control how expressions are parsed and which operators are grouped with which operands. They do not control the order in which subexpressions are evaluated.
Given your example
x = a * b / (c + d);
precedence and associativity cause the expression to be parsed as
(x) = ((a * b) / (c + d))
The multiplicative operators * and / have the same precedence and are left-associative, so a * b / (c + d) is parsed as (a * b) / (c + d) (as opposed to a * (b / (c + d))).
So what this tells us is that the result of a * b is divided by the result of c + d, but this does not mean that a * b must be evaluated before c + d or vice versa.
Each of a, b, c, and d may be evaluated in any order (including simultaneously if the architecture supports it). Similarly each of a * b and c + d may be evaluated in any order, and if the same expression is evaluated multiple times in the program, that order doesn't have to be consistent. Obviously both a and b have to be evaluated before a * b can be evaluated, and both c and d have to be evaluated before c + d can be evaluated, but that's the only ordering you can be certain about.
There are operators that force left-to-right evaluation - ||, &&, ?:, and the comma operator, but in general order of evaluation is a free-for-all.
It's not necessarily true to say that the "the parentheses force the addition to take place before the multiplication and the division". You can see this in a disassembly of the code (gcc 10.2.0):
x = a * b / (c + d);
1004010b6: 8b 45 fc mov -0x4(%rbp),%eax
1004010b9: 0f af 45 f8 imul -0x8(%rbp),%eax
1004010bd: 8b 4d f4 mov -0xc(%rbp),%ecx
1004010c0: 8b 55 f0 mov -0x10(%rbp),%edx
1004010c3: 01 d1 add %edx,%ecx
1004010c5: 99 cltd
1004010c6: f7 f9 idiv %ecx
The multiplication was performed first, followed by the addition, then the division.
Nope, you say
Here, the final value of x will become 1. This is because first, the values of c and d will be added together (6+4), then the values of a and b will be multiplied together (2*5), and finally, the division will take place (10/10), resulting in the final value becoming 1, which is then assigned to x.
the evaluation order establishes that 6 + 4 will be evaluated before the division is done... but not that the compiler cannot first arrange to evaluate first c * d (because the multiplication operators are left associative, and this means --also-- that the multiplication will be made before the division). You don't even know (except if you look at the assembler output) which order of subexpression evaluation will the compiler select. As stated, the full parenthesized expression would be:
(x = ((a * b) / (c + d)));
so, the compiler will decide to start first with a * b or c + d indistinctly. Then it will do the other operation, then it will do the division, and finally the assignment. But beware, because the assignment requires the address of x and not its value (it's an lvalue), so the address of x can be calculated at any point, but before the assignment is made. Finally, the (unused) value of the assignment is thrown.
a possible order could be:
calculate a * b
calculate address of x
calculate c + d
calculate the division (a*b)/(c+d)
store the result at position &x.
a different one:
calculate c + d
calculate a * b
calculate the division (a*b)/(c+d)
calculate address of x
store the result at position &x.
but you could also calculate the address of x in the first step.
When i compile this code,it showing an error as lvalue required as increment operand
int main(void)
{
int x,y,z;
x=8++;
y=++x++;
z=(x+y)--;
printf("x=%d,y=%d,z=%d",x,y,z;
return 0;
}
When you write something++ or ++something it's roughly equivalent to
something = something + 1
(the difference between something++ and ++something is in what you get when you assign the result to something else).
Because of this, the operand of ++ has to be something you can assign to.
8++ is equivalent to 8 = 8 + 1, but you can't assign to a number.
++x++ would be equivalent to something like (x = x + 1) = (x = x + 1) + 1, I can't even fathom what this could be intended to mean.
(x+y)-- is equivalent to (x + y) = (x + y) - 1. You can't assign to an addition expression (which variable would you be setting)?
You should only use ++ or -- when you actually want to update a variable. It's not a general replacement for + 1 or - 1. So your program should be:
x = 8 + 1;
y = 1 + x + 1;
z = (x + y) - 1;
This will print
x = 9, y = 11, z = 19
constant cannot be changed. 8 is a constant value. (x+y) is also not the value which can be incremented and stored somewhere.
x++ uses the value of x then increments the x. So the lvalue is changed itself not only the result of the operation.
correct is
z=(x+y)-1;
x=8+1;
I have a problem understanding the output of the code. Any explanation please...
#include<stdio.h>
void main()
{
int x=2,y=5;
x*=y+1;
printf("%d",x);
}
The output is as 12. But as per my understanding x*=y+1;is x=x*y+1; but as per operator precedence x*y should be evaluated followed by adding 1 so it should be 10+1=11. But it is 12 — can anyone explain please?
It will be evaluated as
x = x * (y + 1);
so
x = 2 * ( 5 + 1 )
x = 12
What's going on here is how the order of operations happens in programming.
Yes, if you were to have this equation x*y+1 it would be (x * y ) + 1 and result in eleven.
But in programming, the equation to the right of the = sign is solved for prior to being modified by the symbol proceeding the = sign. In this equation it is multiplied.
So x *= y + 1 is actually x = x * ( y + 1 ) which would be 12.
^ In this case, the asterisk(*) is multiplying the entire equation on the right hand side by x and then assigning that outcome to x.
It is translated into : x = x*(y+1);
So very obviously it prints out 12.
Your understanding is correct but it's somthing like this:
x*=y+1; => x = x * (y + 1);
Now apply BODMAS
x *= y + 1 is x = x * (y + 1)
Operator + has higher precedence than operator *=.
x*=y; works like x=x*y;
and here x*=(y+1) is getting expanded like x = x * (y + 1);
*= and similar ones are a type of C assignment operators, i.e. these operators are different from * and alike.
Now from C operator precedence, these operators have lowest precedence (higher than ,) hence y + 1 will be evaluated first, then *= will be evaluated and result will be assigned to x.
It evaluates as
x = x * (y + 1);
so
x = 2 * (5 + 1) = 12
Take a look at Operators order, you will see why in this case it is evaluated like that.
Here from operator procedure in c you can see
Addition/subtraction assignment has lower procedure than simply add operation.
so here
x*=y+1;
+ get executed first.
so
x = x * (6)
so x = 2 * 6
x = 12;
I have done a ton of research as to how the order of evaluation goes - but cannot figure out how it would go for this equation:
z = !x + y * z / 4 % 2 - 1
My best guess is (from left to right):
z = !x + {[([y * z] / 4) % 2] - 1}
Order of evaluation and operator precedence are two different things.
Your best guess is correct. All the multiplicative operators * / % have the same precedence, and bind left-to-right. The additive operator - has lower precedence. The unary ! operator binds more tightly than the multiplicative or additive operators. And the assignment operator = has very low precedence (but still higher than the comma operator).
So this:
z = !x + y * z / 4 % 2 - 1
is equivalent to this:
z = (!x) + (((y * z) / 4) % 2) - 1
But the operands may legally be evaluated in any order (except for certain operators like &&, ||, ,, which impose left-to-right evaluation). If the operands are simple variables, this probably doesn't matter, but in something like:
z = func(x) * func(y);
the two function calls may occur in either order.
If you can't understand it, rewrite your expression
z = !x + y * z / 4 % 2 - 1
notx = !x; /* you can move this line 1, 2, or 3 lines down */
tmp1 = y * z;
tmp2 = tmp1 / 4;
tmp3 = tmp2 % 2;
tmp4 = notx + tmp3;
tmp5 = tmp4 - 1;
The question is:
int z, x=5, y=-10 ,a=4, b=2;
z = x++ - --y * b / a;
Just wanted to know the output and how --y will work for the negative value of 'y'. What will be the precedence of solving this?
int z, x=5, y=-10 ,a=4, b=2;
z = x++ - --y * b / a;
z = 5++ - --(-10) * 2 / 4 // Suffix ++/-- goes first
z = 5 - --(-10) * 2 / 4 // Prefix ++/-- is next
z = 5 - (-11) * 2 / 4 // and then * and /
z = 5 - (-22) / 4
z = 5 - (-5)
z = 10
Unlike y, x keeps it's value because in suffix notation the operator returns the original value not the modified one. (Someone else linked the operator precedence page so I won't)
It will be evaluated based on the Operator Precedence or "Order of Operations" - http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
These two are equivelent according to Order of operations
z = x++ - --y * b / a;
z = (x++) - (((--y) * b) / a);
The precedence of the operations is
z = ((x++) - (((--y) * b) / a));
IOW,
The result of --y must be known before computing --y * b;
The result of --y * b must be known before computing --y * b / a (* and / have the same precedence, but are left-associative, so a / b * c would be parsed as (a / b) * c);
The result of x++ must be known before computing x++ - --y * b / a
And finally, the result of x++ - --y * b / a must be known before assigning the result to z.
However...
Note that precedence is not the same thing as order of evaluation. Each of the individual expressions x++, --y, b, and a may be evaluated in any order. The compiler may choose to evaluate x++, then a, then b, then --y. The compiler may choose to evaluate --y * b / a before evaluating x++. The compiler may choose to defer applying the side effects to x++ and --y until after the assignment of the result to z.
y will decrement before the = operation because the -- precedes y and
x will increment AFTER the = operation because the ++ is after the x.
for example:
int i = 2, y = 3, z;
z = ++i + ++y; //3 + 4
or
int i = 2, y = 3, z;
z = --i + --y; //1 + 2
and
int i = 2, y = 3, z;
z = i++ + y++; //2 + 3
Notice in the last example that it is still 2 + 3. That is because the ++ is after i and y so they are incremented after the = statement.
Knowing this, just apply your normal order of operations
(1. Parentheses 2. Exponents 3. Multiplication/Divison 4. Addition/Subtraction) to solve the problem. Since the multiplication and division segments are right next to eachother just read from left to right for that part.
int z, x=5, y=-10 ,a=4, b=2;
z = x++ - --y * b / a;
y = --y
y = -11
z = 5 - -11 * 2 / 4
z = 5 - -22 / 4
z = 5 - -5
z = 10
x = 5++
x = 6
That's my thought process for this: I interperet the values of x and y based off the location of the ++ and -- and then first mulitply -y * b and then divide that value by a and then add that value to x and then finally increment x. Remember when multiplication and division are right next to each-other just read left to right.