As the title says I found such a sentence in some C lecture notes.
I can't invent any example proving that sentence.
In my opinion every of assignment operations is evaluated once, because when we want it to be evaluated more than once we put in in a loop. What am I missing then?
I've searched but couldn't find an answer here on SO.
C says:
(C99, 6.5.16.2p3) "A compound assignment of the form E1 op= E2 differs from the simple assignment expression E1 = E1 op (E2) only in that the lvalue E1 is evaluated only once."
Below are some examples of why it matters:
Example 1:
a[i++] += 1;
is the same as:
a[i] = a[i] + 1; i++;
because the left operand of += is evaluated once.
If it was not evaluated once it would be the same as:
a[i++] = a[i++] + 1;
which is of course different (and undefined behavior BTW).
Example 2:
*foo() += 1;
assuming foo here returns a pointer to an object of a scalar type and produces side effects (for example it prints a string on the terminal). With the compound assignment operator it will print the string only once and not two times.
Example 3:
REG |= 0x01;
assuming REG here is an IO register (something like #define REG (*(volatile uint8_t *) 0x42)) and that every read to this specific IO register triggers a hardware event. The register will be read only once with the compound assignment operator and not two times.
EDIT: following #R. comment I striked the example 3. I think most compilers do not perform a read in this expression: REG = 31 or two reads with this expression: REG = REG | 0x01.
Usually the += operator is introduced in the following way:
x += y;
x = x+y; // does the same
However, the note tries to tell you that this is in fact not accurate, as the left side of = and += might be any expression. As others have stated this can lead to undefined behaviour, but that's not the core of the issue.
For instance:
char* f() {
static char value = 'a';
printf("%c\n",value);
return &value;
}
void g() {
*f() = 'b'; // assigns 'b' which was 'a'
*f() += 2; // changes 'b' to 'd'
*f() = 'b';
*f() = *f() + 2; // changes 'b' to 'd'
}
The difference is that f is executed twice in the last line, while it is executed once in the second.
Your question is very unclear and poorly worded, but I suspect what your note was in reference to is that the combined arithmetic+assignment operators allow you to do certain things without writing (and thus evaluating) the expression for the lvalue more than once. For instance,
*p++ += *q++; /* p is incremented once, as desired */
*p++ = *p++ + *q++; /* undefined behavior */
It especially matters when you'll be using these in macros, for instance:
#define ACCUM(d,s) (d)+=(s) /* good */
#define ACCUM(d,s) (d)=(d)+(s) /* dangerous */
Don't have anything to compile with handy but here is an interesting tidbit:
var1 += var++ would change the value of var1 to var1 + var
however
var1 += ++var would change the value of var1 to var1 + (var + 1)
There are some compound assignment operation in C. for e.g. +=,-=, *=,/=,%=
for e.g. i += 1 It increments the value of i by 1 like i++.
There are number of compound assignment operators. for eg. +=,-=,*=,/=,%=
as a+=b will give a=a+b
for more details click on this
Related
What does the , operator do in C?
The expression:
(expression1, expression2)
First expression1 is evaluated, then expression2 is evaluated, and the value of expression2 is returned for the whole expression.
I've seen used most in while loops:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
It will do the operation, then do a test based on a side-effect. The other way would be to do it like this:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
The comma operator will evaluate the left operand, discard the result and then evaluate the right operand and that will be the result. The idiomatic use as noted in the link is when initializing the variables used in a for loop, and it gives the following example:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
Otherwise there are not many great uses of the comma operator, although it is easy to abuse to generate code that is hard to read and maintain.
From the draft C99 standard the grammar is as follows:
expression:
assignment-expression
expression , assignment-expression
and paragraph 2 says:
The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value. 97) If an attempt is made to modify the result of a comma operator or to access it after the next sequence point, the behavior is undefined.
Footnote 97 says:
A comma operator does not yield an lvalue.
which means you can not assign to the result of the comma operator.
It is important to note that the comma operator has the lowest precedence and therefore there are cases where using () can make a big difference, for example:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
will have the following output:
1 4
The comma operator combines the two expressions either side of it into one, evaluating them both in left-to-right order. The value of the right-hand side is returned as the value of the whole expression.
(expr1, expr2) is like { expr1; expr2; } but you can use the result of expr2 in a function call or assignment.
It is often seen in for loops to initialise or maintain multiple variables like this:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
Apart from this, I've only used it "in anger" in one other case, when wrapping up two operations that should always go together in a macro. We had code that copied various binary values into a byte buffer for sending on a network, and a pointer maintained where we had got up to:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Where the values were shorts or ints we did this:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Later we read that this was not really valid C, because (short *)ptr is no longer an l-value and can't be incremented, although our compiler at the time didn't mind. To fix this, we split the expression in two:
*(short *)ptr = short_value;
ptr += sizeof(short);
However, this approach relied on all developers remembering to put both statements in all the time. We wanted a function where you could pass in the output pointer, the value and and the value's type. This being C, not C++ with templates, we couldn't have a function take an arbitrary type, so we settled on a macro:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
By using the comma operator we were able to use this in expressions or as statements as we wished:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
I'm not suggesting any of these examples are good style! Indeed, I seem to remember Steve McConnell's Code Complete advising against even using comma operators in a for loop: for readability and maintainability, the loop should be controlled by only one variable, and the expressions in the for line itself should only contain loop-control code, not other extra bits of initialisation or loop maintenance.
It causes the evaluation of multiple statements, but uses only the last one as a resulting value (rvalue, I think).
So...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
should result in x being set to 8.
As earlier answers have stated it evaluates all statements but uses the last one as the value of the expression. Personally I've only found it useful in loop expressions:
for (tmp=0, i = MAX; i > 0; i--)
The only place I've seen it being useful is when you write a funky loop where you want to do multiple things in one of the expressions (probably the init expression or loop expression. Something like:
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
Pardon me if there are any syntax errors or if I mixed in anything that's not strict C. I'm not arguing that the , operator is good form, but that's what you could use it for. In the case above I'd probably use a while loop instead so the multiple expressions on init and loop would be more obvious. (And I'd initialize i1 and i2 inline instead of declaring and then initializing.... blah blah blah.)
I'm reviving this simply to address questions from #Rajesh and #JeffMercado which i think are very important since this is one of the top search engine hits.
Take the following snippet of code for example
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
It will print
1 5
The i case is handled as explained by most answers. All expressions are evaluated in left-to-right order but only the last one is assigned to i. The result of the ( expression )is1`.
The j case follows different precedence rules since , has the lowest operator precedence. Because of those rules, the compiler sees assignment-expression, constant, constant .... The expressions are again evaluated in left-to-right order and their side-effects stay visible, therefore, j is 5 as a result of j = 5.
Interstingly, int j = 5,4,3,2,1; is not allowed by the language spec. An initializer expects an assignment-expression so a direct , operator is not allowed.
Hope this helps.
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.
Does the following code invoke undefined behavior in C?
int a = 1, b = 2;
a = b = (a + 1);
I know that the following does invoke UB:
a = b = a++;
The reason is that it violates the following clause from the standard:
Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the
value to be stored.
However, the first snippet does not violate this clause. A coworker says that statement a = b = a+1 can mean either
a = a + 1;
b = a + 1;
or
b = a + 1;
a = b;
I think that due to the "right-to-left" associativity of =, it always must mean a = (b = (a+1)), not
a = a + 1;
b = a + 1;
I'm not positive, though. Is it UB?
IMHO, a = b = a+1 is well-defined.
Here. you're not changing the value of a, just using it, in case of a+1.
To be explicit, according to the "right-to-left" associativity of = operator, you can break down the above as,
b = a + 1; //a does not change here, only the value is used.
a = b;
Here is C99's full list of sequence points (adapted from C99, Annex C):
during a function call, after the arguments have been evaluated and before any part of the function body is executed;
at the end of the first operand of the following operators: &&, ||, ?:, ,;
at the end of a full declarator;
at he end of a full expression (an initializer, the expression in an expression statement, the expression in a return statement, each of the expressions in a for statement, or the controlling expression of an if, switch, while, or do statement);
immediately before a library function returns;
after the actions associated with each formatted input/output function conversion specifier;
immediately before and immediately after each call to a comparison function; and also between any call to a comparison function and any movement of the objects passed as arguments to that call (refers to bsearch() and qsort().
Considering your code in that light:
int a = 1, b = 2;
a = b = (a + 1);
there are sequence points
after a = 1 (full declarator)
after b = 2 (full declarator)
at the end of the second statement. (full expression)
The whole of a = b = (a + 1) is a single expression statement, and it contains no internal sequence points. However, it does not violate the prohibition against an object having its value modified more than once between sequence points: a and b are each modified exactly once in the whole statement.
a = b = a + 1; is the same as :
b = a + 1;
a = b;
You do not change the value of the left hand side in the right hand sides, so it is well defined.
a = a++;
is different compared to
a = a+1;
In the second case you are not modifying the value of a by doing a+1 whereas in the first case the value of a is being changed which will lead to undefined behavior.
What is the difference between increment operator ++ and an addition + operator? Why can't we can use + instead of ++?
What are the advantages of ++/-- operators over +/-? Where exactly are they applicable?
x++;
v.s.
x = x + 1;
The main advantage comes from pre-increment v.s. post increment:
e.g.
x = 1;
y = 1;
a = x + 1; // a is 2, x is 1 - e.g. does not modify x
a = ++x; // a is 1, x is 2
b = y++; // b is 2, y is 2
The major downside is that stuff like
a = ++x + x--;
is undefined behavior. Completely compiler dependent and WILL make life hell for anyone trying to figure out the "bug".
The only difference that is given by the C standard is the number of evaluations of x. For normal variables the difference usually doesn't matter. If the compiler can prove that in x = x + 1 the two evaluations of x should give the same value it might optimize this out.
If x is e.g declared volatile or involves the evaluation of a function, the evaluation must be done twice. Example:
unsigned* f(void);
then
*f() = *f() + 1;
is quite different from
++(*f());
The unary operators (++, --) are mainly there for convenience - it's easier to write x++ than it is to write x = x + 1 for example.
++ can also be used to do a 'pre-increment' or a 'post-increment'. If you write x++ then the value of x is increased and the original value of x is returned. For example:
int a = 0;
int x = 0;
a = x++; // x is now equal to 1, but a is equal to 0.
If you write ++x, x is still incremented, but the new value is returned:
int a = 0;
int x = 0;
a = ++x; // Both a and x now equal 1.
There is also usually a minor difference in the compiler's implementation as well. Post-increment (x++) will do something like this:
Create a temporary variable
Copy x to the temporary variable
Increment x
Return the temporary variable
Whereas pre-increment (++x) will do something like this:
Increment x
Return x
So using pre-increment requires less operations than post-increment, but in modern day systems this usually makes no worthwile difference to be a decent way of optimising code.
You could in fact use addition:
a = a + 1
But most people prefer the shorter version. In some languages it actually avoids the need to copy the value to a new location, but as nneonneo has helpfully pointed out, the C compiler is likely to optimise this for you.
"++" means "plus one"
eg
int x = 5;
x++; // the same as x = x + 1
cout << x; // will print 6
"+" is the known plus operator
++ is a convenience syntax. It does not really add capability to the language, but it adds a way of writing some common operations more concisely.
As a standalone statement a++; is identical to a+=1; is identical to a=a+1;
a++ can be useful in some situations that would otherwise need two statements:
while (a < N) doSomethingWith(a++);
is just a shorter form of
while (a<N)
{
doSomethingWith(a);
a=a+1;
}
I don't think there is anything you can write with an a++ that you couldn't also write with an a=a+1, but you can't just do a 1 for 1 substitution. Sometimes the 2nd form will require more code to be equivalent, since the 1st performs two things: produce the value of a, and then increment a. The a=a+1 form produces the value of a after the increment, so if you need the original value, you need a separate statement to process that first.
The difference between using the increment operator(ie. value++) vs using the addition operator(ie. value + 1) is that the first one sometimes can cause mutation especially if we are accessing a global variable inside a function;
Using increment operator.
// The global variable
var fixedValue = 4;
function incrementer () {
// Only change code below this line
return fixedValue ++;
// Only change code above this line
}
var newValue = incrementer(); // Should equal 5
console.log(fixedValue); // Should print 5
Using addition operator.
// The global variable
var fixedValue = 4;
function incrementer () {
// Only change code below this line
return fixedValue + 1;
// Only change code above this line
}
var newValue = incrementer(); // Should equal 5
console.log(fixedValue); // Should print 4
increment doing on register but addition do by ALU we can use + instead of increment but increment is faster
What does the C standard (preferably C89,90) say about:
int a,b;
a = 4;
b = (a += 1);
?
I have tested it and the result is b=5, which is what I expect. I just want to be reassured by the Standard. The same applies to analogous operators like *=, /=, &=, etc. I know that = is sure to return the value of the left hand side after the assignment. I just want to know if +=, *=, etc. behave the same way, according to the standard.
Assignment operators do not "return" a value: they yield one, or as the standard puts it, have one.
The value is of the left operand, although it won't be an lvalue. Here's the excerpt:
(3.3.16) An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
All of = *= /= %= += -= <<= >>= &= ^= |= are assignment operators so they behave the same way in this regard.
It is not a problem unless there are side-effects.
The assignment operator is not a sequence point, which means that there is no guarantee on order of evaluation.
If you use it as you have given (b = (a += 1);), it is not a problem.
However, in other cases, it may be a problem, for example:
b = (a += 1) + a; // undefined
Notice that in this example, the variable a is referred to twice. What that means is that we don't know whether (a += 1) or a is evaluated first. So we don't know if the 2nd reference to a will be before or after 1 was added to it.
If you only refer to each variable you assign with += and co. once, then side-effects are not a problem, and you can count on += and related operators to return the value after assignment.
This should result in b = 5 and a = 5.
This is because a+=1 takes a and adds 1 to it. Then it assigns a to b.
I'm kind of confused on your question, but *=, /=, -= all work the same way.
For example, you could just have int c = 7; then on the next line do c*=3. This will make c = 21. If in your example, you didn't want a = 5; then just don't do a+=1, and instead, do a+1.