My professor and I are engaging in a bit of a debate about the += operator in C. He says that += or =+ will work, but he is not certain why =+ works.
int main()
{
int i = 0, myArray[5] = {1,1,1,1,1};
while(i < 5)
{
myArray[i] += 3 + i;
printf("%d\n", myArray[i]);
i++;
}
system("pause");
}
The output will yield 4, 5, 6, 7, 8. Changing the += operator to =+ yields the same results. However -= does not do the same as =- (which is obvious as it treats the 3 as a 3).
So C gurus:
Why does this work with =+?
How does a C compiler treat =+ versus +=?
He is wrong; += is completely different from =+.
The expression x =+ 3 is parsed as x = (+3).
Here, + becomes the (rather useless) unary + operator. (the opposite of negation)
The expression x =- 3 is parsed as x = (-3), using the unary negation operator.
Your professor is remembering ancient versions of C in which =+, =-, =* etc did in fact mean the same thing as +=, -=, *= etc. (We're talking older than the version generally referred to as "K&R" here. Version 6 UNIX, if memory serves.)
In current versions of C, they do not mean the same thing; the versions with the equals sign first will be parsed as if there was a space in between the equals and whatever comes after. This happens to produce a valid program (albeit not a program that does what you expect) for =- and =+ because - and + can be used as unary operators.
=* or =/ could be used to settle the argument. a *= 3 will multiply a by three, and a /= 3 will divide it by three, but a =* 3 is a semantic error (because unary * can only be applied to pointers) and a =/ 3 is a syntax error (because / can not be used as an unary operator).
Code
myArray[i] += 3 + i;
will yield myArray[i] = myArray[i] + 3 + i;
whereas
myArray[i] =+ 3 + i;
yields myArray[i] = 3 + i
that's what I got.
+ is also a unary operator as is -.
Related
In the following function:
int fun(int *k) {
*k += 4;
return 3 * (*k) - 1;
}
void main() {
int i = 10, j = 10, sum1, sum2;
sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);
}
You'd get sum 1 to equal 46, and sum 2 to equal 48. How would the function run if there were no precedence rules?
How drastically difference would things run without consistent precedence rules?
The precedence rules tell us how an expression is structured, not how it is evaluated. In sum1 = (i / 2) + fun(&i);, the rules tell us things including:
i / 2 is grouped together because it is in parentheses; it cannot form, for example, (sum1 = i) / 2 + fun(&i);.
(i / 2) and fun(&i) are grouped together because + has higher precedence than =, making sum1 = ((i / 2) + fun(&i); rather than (sum1 = (i / 2)) + fun(&i);.
The precedence rules do not tell us whether i / 2 or fun(&i) is evaluated first. In fact, no rules in the C standard specify whether i / 2 or fun(&i) is evaluated first. The compiler may choose.
If i / 2 is evaluated first, the result will be 10 / 2 + 41 and then 5 + 41 and finally 46. if fun(&i) is evaluated first, the result will be 14 / 2 + 41 and then 7 + 41 and finally 48. Your compiler chose the former. It could have chosen the latter.
How would the function run if there were no precedence rules?
If there were no rules, we would not know how the function would be executed. The rules are what tell us how it will be executed.
Some comments assert that the behavior of this program is undefined. That is incorrect. This misunderstanding comes from C 2018 6.5 2, which says:
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined…
In your code, i / 2 uses i and fun(&i) contains a “side effect” on i (changing its value via an assignment). If these were unsequenced, the behavior would be undefined. However, there is a sequence point after evaluating the argument to fun and before calling it, and there are sequence points after each full expression in fun, including its return statement. Thus, there is some sequencing of the uses of i and the side effects on it. This sequencing is incompletely determined by the rules of the C standard, but it is, as defined by the standard, indeterminately sequenced, not unsequenced.
What is the real advantage of using compound assignment in C/C++ (or may be applicable to many other programming languages as well)?
#include <stdio.h>
int main()
{
int exp1=20;
int b=10;
// exp1=exp1+b;
exp1+=b;
return 0;
};
I looked at few links like microsoft site, SO post1, SO Post2 .
But the advantage says exp1 is evaluated only once in case of compound statement. How exp1 is really evaluated twice in first case? I understand that current value of exp1 is read first and then new value is added. Updated value is written back to the same location. How this really happens at lower level in case of compound statement? I tried to compare assembly code of two cases, but I did not see any difference between them.
For simple expressions involving ordinary variables, the difference between
a = a + b;
and
a += b;
is syntactical only. The two expressions will behave exactly the same, and might well generate identical assembly code. (You're right; in this case it doesn't even make much sense to ask whether a is evaluated once or twice.)
Where it gets interesting is when the left-hand side of the assignment is an expression involving side effects. So if you have something like
*p++ = *p++ + 1;
versus
*p++ += 1;
it makes much more of a difference! The former tries to increment p twice (and is therefore undefined). But the latter evaluates p++ precisely once, and is well-defined.
As others have mentioned, there are also advantages of notational convenience and readability. If you have
variable1->field2[variable1->field3] = variable1->field2[variable2->field3] + 2;
it can be hard to spot the bug. But if you use
variable1->field2[variable1->field3] += 2;
it's impossible to even have that bug, and a later reader doesn't have to scrutinize the terms to rule out the possibility.
A minor advantage is that it can save you a pair of parentheses (or from a bug if you leave those parentheses out). Consider:
x *= i + 1; /* straightforward */
x = x * (i + 1); /* longwinded */
x = x * i + 1; /* buggy */
Finally (thanks to Jens Gustedt for reminding me of this), we have to go back and think a little more carefully about what we meant when we said "Where it gets interesting is when the left-hand side of the assignment is an expression involving side effects." Normally, we think of modifications as being side effects, and accesses as being "free". But for variables qualified as volatile (or, in C11, as _Atomic), an access counts as an interesting side effect, too. So if variable a has one of those qualifiers, a = a + b is not a "simple expression involving ordinary variables", and it may not be so identical to a += b, after all.
Evaluating the left side once can save you a lot if it's more than a simple variable name. For example:
int x[5] = { 1, 2, 3, 4, 5 };
x[some_long_running_function()] += 5;
In this case some_long_running_function() is only called once. This differs from:
x[some_long_running_function()] = x[some_long_running_function()] + 5;
Which calls the function twice.
This is what the standard 6.5.16.2 says:
A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once
So the "evaluated once" is the difference. This mostly matters in embedded systems where you have volatile qualifiers and don't want to read a hardware register several times, as that could cause unwanted side-effects.
That's not really possible to reproduce here on SO, so instead here's an artificial example to demonstrate why multiple evaluations could lead to different program behavior:
#include <string.h>
#include <stdio.h>
typedef enum { SIMPLE, COMPOUND } assignment_t;
int index;
int get_index (void)
{
return index++;
}
void assignment (int arr[3], assignment_t type)
{
if(type == COMPOUND)
{
arr[get_index()] += 1;
}
else
{
arr[get_index()] = arr[get_index()] + 1;
}
}
int main (void)
{
int arr[3];
for(int i=0; i<3; i++) // init to 0 1 2
{
arr[i] = i;
}
index = 0;
assignment(arr, COMPOUND);
printf("%d %d %d\n", arr[0], arr[1], arr[2]); // 1 1 2
for(int i=0; i<3; i++) // init to 0 1 2
{
arr[i] = i;
}
index = 0;
assignment(arr, SIMPLE);
printf("%d %d %d\n", arr[0], arr[1], arr[2]); // 2 1 2 or 0 1 2
}
The simple assignment version did not only give a different result, it also introduced unspecified behavior in the code, so that two different results are possible depending on the compiler.
Not sure what you're after. Compound assignment is shorter, and therefore simpler (less complex) than using regular operations.
Consider this:
player->geometry.origin.position.x += dt * player->speed;
versus:
player->geometry.origin.position.x = player->geometry.origin.position.x + dt * player->speed;
Which one is easier to read and understand, and verify?
This, to me, is a very very real advantage, and is just as true regardless of semantic details like how many times something is evaluated.
Advantage of using compound assignment
There is a disadvantage too.
Consider the effect of types.
long long exp1 = 20;
int b=INT_MAX;
// All additions use `long long` math
exp1 = exp1 + 10 + b;
10 + b addition below will use int math and overflow (undefined behavior)
exp1 += 10 + b; // UB
// That is like the below,
exp1 = (10 + b) + exp1;
A language like C is always going to be an abstraction of the underlying machine opcodes. In the case of addition, the compiler would first move the left operand into the accumulator, and add the right operand to it. Something like this (pseudo-assembler code):
move 1,a
add 2,a
This is what 1+2 would compile to in assembler. Obviously, this is perhaps over-simplified, but you get the idea.
Also, compiler tend to optimise your code, so exp1=exp1+b would very likely compile to the same opcodes as exp1+=b.
And, as #unwind remarked, the compound statement is a lot more readable.
So to be up front, this is related to a homework assignment that I need guidance with. I don't need code or anything, but this is driving me crazy and I need some clarification. I'm not even asking the question in the book.
I have the following code:
int fun(int *c){
*c += 10;
return *c ;
}
void main(){
int a, b;
a = 10;
b = a + fun(&a);
printf("value of a is %d\n", a);
printf("With the function call on the right, ");
printf(" b is: %d\n", b);
a = 10;
b = fun(&a) + a;
printf("With the function call on the left, ");
printf(" b is: %d\n", b);
}
When I run it, I get "value of a is 20" and "with the function call on the right, 40" and "with the function call on the left, 40".
What I am confused about is that I had a very similar question right before
#include<stdio.h>
int fun(int *k) {
*k += 4;
return 3 * (*k) - 1;
}
void main() {
int i = 10, j = 10, sum1, sum2;
sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);
printf("%d", sum1);
}
And the answer comes out to 46 for sum1 and 48 for sum2 which in my head makes sense with left to right evaluation in codepad.org's compiler. But in Pelles C compiler it comes out to 48. You can see that the code from the first problem is laid out pretty much exactly the same.
I did find this link: Parameter evaluation order before a function calling in C which seems to explain this inconsistency but I want to make sure I'm not way off in my line of thinking. So would it be safe to say that it depends on the compiler and what the compiler feels is most efficient?
In both these expressions
sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);
you have unspecified behavior, because the order of evaluation of the subexpressions of + is unspecified. The compiler is free to evaluate (i/2) and (j/2) before or after the call, as it sees fit.
Unlike && and || operators that force evaluation of their left side before their right side, +, -, *, /, %, and all the bitwise operators allow the compiler to pick the most convenient order of evaluation, depending on its optimization strategy. This means that different compilers may decide to evaluate the sides of + differently.
What this means from the practical perspective is that you should use expressions with side effects no more than once in the same expression. You can rewrite both your expressions to force the order of evaluation that you want, for example
sum1 = i/2;
sum1 += fun(&i);
or
sum2 = sun(&j);
sum2 += j/2;
This is a question from kn king's c programming : a modern approach. I can't understand the solution given by him:-
The expression ++i is equivalent to (i += 1). The value of both expressions is i after
the increment has been performed.
How do I understand this anyway?
i = 10
printf("%d", i++);
will print 10, where as
printf("%d", ++i);
will print 11
X = i++ can be thought as this
X = i
i = i + 1
where as X = ++i is
i = i + 1
X = i
so,
printf ("%d", ++i);
is same as
printf ("%d", i += 1);
but not
printf ("%d", i++);
although value of i after any of these three statements will be the same.
The solution means to say that there is no difference, ++i has the same meaning as (i += 1) no matter what i happens to be and no matter the context of the expression. The parentheses around i += 1 make sure that the equivalence holds even when the context contains further arithmetics, such as ++i * 3 being equivalent to (i += 1) * 3, but not to i += 1 * 3 (which is equivalent to i += 3).
The same would not apply to i++, which has the same side effect (incrementing i), but a different value in the surrounding expression — the value of i before being incremented.
++i is the pre-increment operator. It increments i before setting and returning the value (which is obviously i + 1).
Now, i++ is the post-increment operator. It increments i after the whole instruction it appears in is evaluated.
Example:
int i = 0;
std::cout << ++i << std::endl; /* you get 1 here */
std::cout << i++ << std::endl; /* you still get 1 here */
std::cout << i << std::endl; /* you get 2 here */
One difference that has not been brought up so far is readability of code. A large part of loops use increment by one and common practice is to use i++/++i when moving to the next element / incrementing an index by 1.
Typically i+= is used in these cases only when the increment is something other than 1. Using this for the normal increment will not be dangerous but cause a slight bump in the understanding and make the code look unusual.
Difference between both are: ++ is a unary operator while + is a binary operator....
If we consider execution time: i++ is more faster than i=i+1.
No of machine cycles differs to execute the same set of code, thats the reason ++ operators are always prefered for Loops.
Refer to this thread for more info
I think they are totally the same. There is one thing maybe interesting. The ++i is equal to (i+=1) but not i+=1; The difference is the brace. Because i += 1 may depend on the context and it will have different interpretation.
In a normal operation without assignation:
++i and i++
increase the variable in 1. In pseudo assembly both code it is:
inc i
but If you assign the value the order of ++ is relevant:
x = i++
produce:
mov x, i
inc i
x = ++i
produce:
inc i
mov x, i
In the case of:
i += 1
it will produce:
add i,1
but because compilers optimize the code it also will produce in this case:
inc i
This question already has answers here:
Is a += b more efficient than a = a + b in C?
(7 answers)
Closed 9 years ago.
what is the difference between i = i + j; and i += j; in C?
Are they equivalent? Is there any side effect of i?
I was trying to check the assignment mechanism in C using the GCC compiler.
They're almost the same. The only difference is that i is only evaluated once in the += case versus twice in the other case.
There is almost no difference, but if i is a complex expression, it is only computed once. Suppose you had:
int ia[] = {1, 2, 3, 4, 5};
int *pi = &(ia[0]); // Yes, I know. I could just have written pi = ia;
*pi++ += 10;
// ia now is {11, 2, 3, 4, 5}.
// pi now points to ia[1].
// Note this would be undefined behavior:
*pi++ = *pi++ + 10;
i = i + j is equivalent to i += j but not same.
In some cases(rare) i += j differs from i = i + j because i itself has a side effect.
Also one more problem is operator precedence i.e
i = i * j + k;
is not same as
i *= j + k;
The two statements i = i + j and i += j, are functionally same, in first case you are using the general assignment operation, while the second one uses the combinatorial assignment operator. += is additive assignment operator (addition followed by assignment).
The use of combinatorial assignment operators generates smaller source code that is less susceptible to maintenance errors and also possibly a smaller object code where it would also run faster. Compilation is also likely to be a little faster.
Syntactic sugar baby.
Any differences are just going to come down to compiler implementation.
http://en.wikipedia.org/wiki/Syntactic_sugar
In both cases i (the variable or expression being assigned) must be an lvalue. In most simple cases this will yield code that is identical in both cases so long as i is not declared volatile.
However there are a few cases where a lvalue can be an expression involving operators, and this may cause evaluation of i twice. The most plausible example of an lvalue expression that might be used in that way is perhaps simple dereferencing of a pointer (*p):
*p = *p + j ;
*p += j ;
may generate different code, but it is trivially optimised so I would expect not even without optimisation enabled. Again p cannot be volatile, otherwise the expressions are semantically different.
A less plausible scenario is to use a conditional operator expression as an lvalue. For example the following adds j to b or c depending on a:
(a ? b : c) += j ;
(a ? b : c) = (a ? b : c) + j ;
These might generate different code - the compiler might reasonably not spot that idiom and apply an optimisation. If the expression a has side effects - for example were the expression getchar() == '\n' or a is volatile (regardless of b or c), then they are not equivalent since the second would evaluate to:
c = b + j for the input "Y\n",
b = b + j for input "\n\n",
c = c + j for input "YN".
These points are of course mostly irrelevant - if you write code like that and it does things you did not expect, sympathy may be in short supply!