Advantage of using compound assignment - c

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.

Related

How is this working in c language. Output is 1 and 2 respectively. But how? [duplicate]

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.

How can I save the array values so that it will allow me to perform the other options? [duplicate]

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.

Reverse function has only one argument but recursive function is passing 2 parameters [duplicate]

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.

Assigning Values to variables in c [duplicate]

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 difference between i = i + j; and i += j; in c language? [duplicate]

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!

Resources