Unclear behavior of "," operator in C - c

In a given code I found following sequence,
data = POC_P_Status, TE_OK;
I don't understand what that does mean.
Does the data element receive the first or the second element or something else?
Update:
I read somewhere that this behavior is like this,
if i would write that:
if(data = POC_P_Status, TE_OK) { ... }
then teh if clause will be true if TE_OK is true.
What do you mean?

It stores POC_P_Status into data.
i = a, b; // stores a into i.
This is equivalent to
(i = a), b;
because the comma operator has lower precedence than assignment.

It's equivalent to the following code:
data = POC_P_Status;
TE_OK;
In other words, it assigns POC_P_Status to data and evaluates to TE_OK.
In your first case, the expression stands alone, so TE_OK is meaningful only if it's a macro with side effects. In the second case, the expression is actually part of an if statement, so it always evaluates to the value of TE_OK. The statement could be rewritten as:
data = POC_P_Status;
if (TE_OK) { ... }
From the C11 draft (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf) :
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. 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 undeļ¬ned.
That means that in the expression:
a, b
The a is evaluated and thrown away, and then b is evaluated. The value of the whole expression is equal to b:
(a, b) == b
Comma operator is often used in places where multiple assignments are necessary but only one expression is allowed, such as for loops:
for (int i=0, z=length; i < z; i++, z--) {
// do things
}
Comma in other contexts, such as function calls and declarations, is not a comma operator:
int func(int a, int b) {...}
^
|
Not a comma operator
int a, b;
^
|
Not a comma operator

Related

Chaining assignment in an if condition

Hi just wondering if you use a chained assigment in an if condition, would the leftmost variable be used to check the if condition
like a=b=c , its a thats ultimetly checked and not b or c
#include <stdio.h>
int main()
{
int a, b, c =0;
// does this reduce to a == 100 and the variables b or c are not checked if they are == to 100 but simply assigned the value of 100 ?
if( (a = b = c = 100) == 100)
printf( "a is 100 \n");
return 0;
}
The expression is not actually checking a or b or c.
An assignment expression, like any expression, has a value. And in this case it is the value that is stored. However, the actual storing of the value in an object is a side effect so there's no guarantee that it has happened at the time the comparison operator is evaluated.
So the condition is actually more like:
if (100 == 100)
With the assignment to a, b, and c happening in a manner that is unsequenced with respect to the comparison.
This is spelled out in section 6.5.16p3 of the C standard regarding assignment operators:
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. The type of an assignment expression is the type the left operand would have after lvalue conversion. The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
The condition is always true. Your code is equivalent to:
a = 100;
b = 100;
c = 100;
printf( "a is 100 \n");

C multiple assignments to same variable in short-circuited expression

I have three variables: a, b, c. Let's say they are integers. I want to find the first non-zero value among them, in that particular order, without looping. The following seems to work, but I am not sure if that is because I am lucky, or because the language guarantees it:
int main(int argc, char *argv[]) {
int a = 0;
int b = 3;
int c = 5;
int test;
if ((test = a) != 0 || (test = b) != 0 || (test = c) != 0) {
printf("First non-zero: %d\n", test);
} else {
printf("All zero!\n");
}
return 0;
}
Is the repeated assignment with short-circuiting shown here guaranteed to work as intended, or am I missing something?
This might be one place where a three-letter answer would be acceptable, but a two-letter answer might require more explanation.
It would!
Because of the nature of the OR operator if any of the condition is
true then the test stops.
Thus i think what you did was basically equivalent to:
test = a != 0 ? a : b != 0 ? b : c != 0 ? c : 0;
printf("%d\n",test);
but heck yours looks good.
[update]
As per what chqrlie mentioned it can be further simplified to:
test = a ? a : b ? b : c;
Yes, your expression is fully defined because there is a sequence point at each || operator and the short circuit evaluation guarantees that the first non zero value assigned to test completes the expression.
Here is a crazy alternative without sequence points that may produce branchless code:
int test = a + !!a * (b + !!b * c);
printf("%d\n", test);
The code is very bad practice but it is guaranteed to work fine.
This is because the || and && operators have special characteristics - unlike most operators in C, they guarantee that the evaluation of the left operand is sequenced (executed) before the evaluation of the right operand. This is the reason that the code works. There's also a guarantee that the right operand will not be evaluated if it is sufficient to evaluate the left one ("short circuit"). Summarized in C17 6.5.14/4:
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the
second operand is evaluated, there is a sequence point between the evaluations of the first
and second operands. If the first operand compares unequal to 0, the second operand is
not evaluated.
"Sequence point" being the key here, which is what gives the expression a deterministic outcome.
Had you used pretty much any other operator (like for example bitwise |), then the result would be undefined, because you have multiple side effects (assignments) on the same variable test in the same expression.
A more sound version of the same algorithm would involve storing the data in an array and loop through it.

Evaluation order in a for-loop initialization in C

Consider this C-snippet:
int a;
int b;
for (a = 0, b = a + 1; a < N; a++)
/* Something. */
Does the C specification clearly requires a compiler to keep the statements in the for-initializer in the order they appear?
I am specifically trying to avoid undefined behavior, if, for example, a was in an outer/global scope and the specification was not strict in this specific area. In other words, I want to be sure that the example above has a clear definition for compilers, and not enter gray areas such as a = ++a + b++;.
Not specially in the for-initializer, the expression in left of comma operator (a = 0) will be evaluated first, then the right (b = a + 1) will be evaluated.
N1256 6.5.17 Comma operator
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.

Using increment in ternary operator in C

For the example, after I use
int a = 5, b = 6;
x = (a < b) ? a++ : b++;
x gets the value of a, which is 5, and a increments to 6, which is expected.
When I use
a = (a < b) ? a++ : b++;
After this line, a still remains 5.
But
a = (a++ < b++) ? a : b;
a is now 6.
Why is this happening and why isn't increment operator executed in the first case?
EDIT: Just to clarify, I'm asking why this happens when I'm using these lines separately, one by one, not all three in the same time.
a = (a < b) ? a++ : b++;
here, we stored a in a, and then incremented it. But it is like
a = a++; // as a<b
which shows undefined behaviour.
a = (a++ < b++) ? a : b;
here, a is being incremented at the time of comparison, so now a is 6, which is stored in a.
Both cases involve undefined behaviour of some sort because you are incrementing a, returning a and assigning to a on the left side within 2 sequence points. 3 would be required for a clearly defined result.
In this case :
a = (a < b) ? a++ : b++;
if a is smaller than b
a is returned (value = 5) as the result of the ternary operator
a is incremented (value = 6).
the result of the ternary operator (5) is assigned to the left hand side variable a (over-writing 6)
The order of steps 3 and 4 is not defined. It is equivalent to a = a++;
In this case :
a = (a++ < b++) ? a : b;
If a is smaller that b
a and b are incremented (regardless which is smaller)
a is returned as the result of the ternary operator
it is assigned to the left hand side variable a
The order of steps 2 and 3 is not clearly defined.
It's important to keep track of sequence points in such cases. Relevant rules :
The 1st expression of ternary operator on the left of ? is sequenced before the 2nd or 3rd expressions. And either of them is sequenced before assignment.
The comparison is sequenced before the ?
In expressions like a++ the value is returned before incrementing
Undefined behaviour:
In expressions like a = a++; there is no sequence point between (post)incrementing a and assigning to a on the left side. Both happen after the original value of a is returned
In expressions like a++ ? a : b there is no sequence point between (post)incrementing a and returning a from the ternary operator. Both happen after the ?
The one line that gives you the unexpected result has an error: you are not allow to modify an object (here a) twice in the same expression without separating them by a "sequence point".
The ? in the other one is a sequence point, so that one works.
If you do so (modify twice without sequence point) the behavior of your program becomes undefined. That is you can't make any reasonable assumption of what the program should produce and thus you see some unexpected results that even will vary according to the compiler and its version.
From the horse's mouth:
6.5 Expressions
...
2 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. If there are multiple allowable orderings of the
subexpressions of an expression, the behavior is undefined if such an unsequenced side
effect occurs in any of the orderings.84)
84) This paragraph renders undefined statement expressions such as i = ++i + 1;
a[i++] = i;
while allowing i = i + 1;
a[i] = i;
6.5.15 Conditional operator
...
4 The first operand is evaluated; there is a sequence point between its evaluation and the
evaluation of the second or third operand (whichever is evaluated). The second operand
is evaluated only if the first compares unequal to 0; the third operand is evaluated only if
the first compares equal to 0; the result is the value of the second or third operand
(whichever is evaluated), converted to the type described below.110)
110) A conditional expression does not yield an lvalue.
6.5.16 Assignment operators
...
3 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,111) but is not
an lvalue. The type of an assignment expression is the type the left operand would have
after lvalue conversion. The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands. The evaluations of
the operands are unsequenced.
111) The implementation is permitted to read the object to determine the value but is not required to, even
when the object has volatile-qualified type.
In the expression
a = (a < b ) ? a++ : b++
there is a sequence point between the evaluation of (a < b) and a++, but there is no sequence point between the evaluation of a on the LHS of the = operator and a++; thus, the behavior is undefined.
In the expression
a = (a++ < b++) ? a : b
there is a sequence point between (a++ < b++) and the a on the RHS of the ? operator, but there's no sequence point between the a on the LHS of the = operator and (a++ < b++); again, the behavior is undefined.

Precedence of parentheses between post-fix and pre-fix in C

The C Operator Preference Table notes the higher precedence of ().
Code:
# include <stdio.h>
int main()
{
int temp=2;
(temp += 23)++; //Statement 1
++(temp += 23); //Statement 2
printf("%d",temp);
return 0;
}
My question is while parentheses has higher precedence than pre-fix operator in Statement 2 why there's an error.
In Statement 1 both has same precedence but order of evaluation is from left to right. Still the same error.
Third doubt: operator += has much lower precedence, then why it's causing error.
error: lvalue required as increment operand
An lvalue is a value that some other value can be assigned to (because it is on the left side of the assignment operator). (temp += 23) is a rvalue. Nothing can be assigned to it.
Something else I'd like to add, is that it looks like you're trying to modify a value more than once in an expression. That's undefined behavior according to C99 standard 6.5(2).
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 read only to determine the value to be stored.
And footnote 71) shows the example:
This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

Resources