Does the following chained assignment cause Undefined behavior? - c

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.

Related

Multiple unsequenced modifications to 'a',a = a++ [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 1 year ago.
Why i can't do the following in Objective-C?
a = (a < 10) ? (a++) : a;
or
a = (a++)
The ++ in a++ is a post-increment. In short, a = a++ does the following:
int tmp = a; // get the value of a
a = a + 1 //post-increment a
a = tmp // do the assignment
As noted by others, in C this is actually undefined behavior and different compilers can order the operations differently.
Try to avoid using ++ and -- operators when you can. The operators introduce side effects which are hard to read. Why not simply write:
if (a < 10) {
a += 1;
}
To extend Sulthan's answer, there are several problem with your expressions, at least the simple assignment (case 2).
A. There is no sense in doing so. Even a++ has a value (is a non-void expression) that can be assigned, it automatically assigns the result to a itself. So the best you can expect is equivalent to
a++;
The assignment cannot improve the assignment at all. But this is not the error message.
B. Sulthans replacement of the statement is a better case. It is even worse: The ++ operator has the value of a (at the beginning of the expression) and the effect to increment a at some point in future: The increment can be delayed up to the next sequence point.
The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.
(ISO/IEC 9899:TC3, 6.5.2.4, 2)
But the assignment operator = is not a sequence point (Annex C).
The following are the sequence points described in 5.1.2.3:
[Neither assignment operator nor ) is included in the list]
Therefore the expression can be replaced with what Sulthan said:
int tmp = a; // get the value of a
a = a + 1 //post-increment a
a = tmp // do the assignment
with the result, that a still contains the old value.
Or the expression can be replaced with this code …:
int tmp = a; // get the value of a
a = tmp // assignemnt
a = a + 1 // increment
… with a different result (a is incremented). This is what the error message says: There is no defined sequence (order the operations has to be applied.)
You can insert a sequence point using the comma operator , (what is the primary use of it), …
a++, a=a; // first increment, then assign
… but this shows the whole leak of meaning of what you want to do.
It is the same with your first example. Though ? is a sequence point …:
The following are the sequence points described in 5.1.2.3:
… The end of the first operand of the following operators: […] conditional ? (6.5.15);[…].
… both the increment (a++) and the assignment (a=) are after the ? operator is evaluated and therefore unsequenced ("in random order") again.
To make the comment "Be careful" more concrete: Don't use an incremented object in an expression twice. (Unless there is a clear sequence point).
int a = 1;
… = a++ * a;
… evaluates to what? 2? 1? Undefined, because the increment can take place after reading a "the second time".
BTW: The Q is not related to Objective-C, but to pure C. There is no Objective-C influence to C in that point. I changed the tagging.

What does " = " instead of " == " mean in c if statement?

#include <stdio.h>
int main(){
int b = 10,a;
if (a = 5){
printf("%d",b);
}
}
In the above program if statement always returns true even if i change the data type of the variable "a" from "int" to "char".
What does = mean in the if statement??
= is an assignment operator in C. According to C99 6.5.16:
An assignment operator stores a value in the object designated by the
left operand. An assignment expression has the value of the left
operand after the assignment, but is not an lvalue.
It means that expression a = 5 will return 5 and therefore instructions inside if block will be executed. In contrary, if you replaced it with a = 0 then 0 would be returned by assignment expression and instructions inside if would not be executed.
A single = means an assignment operator, that means you are changing the value of a and using this value in the if statement.
if(a = 5) {
// some code
}
is the same of:
a = 5;
if(a) {
// some code
}
The == means a operation of logical equivalence, witch will return 1 if the two values are the same or 0 if they aren't the same.
Assignment operator returns the assigned value back.
"if" statement decides to true if checked value is other than zero
So:
"if (a=0)" returns false
"if (a=x) where x!= 0" returns true
Thus you should use "==" operator in the if statement as other friends told.
The single = will assign the value 5 to a. Assignment will evaluate true if the assignment value evaluates true (i.e. not 0, null etc). If it evaluates true, the function will branch into the if statement block. And there's the side effect that a gets value 5.
Please note that in C it is allowed in a boolean expression to use the assignment operator. Because of that = as assignment must be a different symbol than = for comparisson.
Because in a language such as BASIC there can be no confusion of whether the programmer means assignment or comparisson, BASIC uses the same symbol for the two meanings:
C:
if ((a=5)==5) ... // a is set to 5 and then compared to 5
Basic:
a = 5 ' assignment
If (a = 5) Then ' comparison

Are "arithmetic expressions" separated by commas allowed in C or we need separate statements for each?

In C, is the following statement
a+=3,b=c*2,d=a+b;
equivalent to the following block of statements:
a+=3;
b=c*2;
d=a+b;
I am sure you got my point. Can we safely use multiple mathematical expressions separated by commas in the same statement in C? And in what cases this can pose problems?
It might be easier if you think of the comma-expression list you present like this:
((a += 3, b = c * 2), d = a + b)
First the innermost comma-expression is evaluated:
a += 3, b = c * 2
That expression will be evaluated in two steps:
a += 3
b = c * 2
The result of a += 3 will be thrown away by the compiler, but the assignment still happens, it's just that the returned result is thrown away. The result of the first comma expression is b (which will be c * 2 (whatever that is)).
The result of the first comma expression is then on the left-hand side of the next comma expression:
b = c * 2, d = a + b
Which will then be sequenced as
b = c * 2
d = a + b
The result of the expression b = c * 2 is thrown away (but as it is still evaluated the assignment still happens), and the result of the complete expression is d (which is a + b).
The result of the whole expression will be d.
They are the same.
In C, the comma operator evaluates its left hand side, ignores the return value (for example the return of x = y is the new value), evaluates the right hand side and returns its result (if any). The use of the comma operator is to evaluate and get the side effects of what's on the left hand without using (e.g. discarding) its value.

Does += return the value of the left hand side after assignment?

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.

Arithmetic assignment operator - left side evaluated only once

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

Resources