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;
Related
The output of:
#include <stdio.h>
int Fun1(int *X)
{
return (*X)++;
}
int main(void)
{
int a = 0, b = 5;
a = Fun1(&b);
printf("a = %d. b = %d.\n", a, b);
}
is:
a = 5. b = 6.
When we return (*X)++, should not the function execution stop when we return (*X), so the ++ is not executed?
The return statement causes its operand to be evaluated. Evaluation of an expression includes both computation of its value and of its side effects.
The C standard specifies the behavior of postfix ++ in 6.5.2.4 2:
The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it)…
Similarly, if we wrote a = b++;, the assignment would not just assign the value and be done. The side effect occurs too.
The side effects are part of what an expression does, per 6.5 1:
An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof…
This:
*X = (*X)++ + ++(*X)
is undefined behavior, so you cannot really predict the result: Why are these constructs using pre and post-increment undefined behavior?
Also, if you want to know what undefined behavior is: Undefined, unspecified and implementation-defined behavior
This:
return (*X)++;
is equivalent to this: (Provided that X is an int)
int tmp = (*X)++;
return tmp;
return does not do anything magical here. I refer to #Eric's answer for a more in depth explanation of postfix operator.
When we return (*X)++, should not the function execution stop when we return (*X), so the ++ is not executed?
No
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");
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.
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.
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.