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
Related
In this youtube video, I came across with the following examples:
However, they doesn't seem correct to me, for the first example:
*ptr++
In my understanding, this means that, if ++ has greated precedence than *, increment the pointer by 1 in pointer arithmetic, then get the value stored in the address which is pointed by this new pointer. So the code
x = *ptr++;
should be equal to,
ptr++;
x = *ptr;
Which is either conflicting with the video, or I am mixing somethings. Can you please tell me if I am right or wrong?
Precedence affects how expressions are structured. It does not affect what the rules of the operations are.
In *ptr++, precedence says the rules for ++ are applied to ptr, and then the rules for * are applied to the result.
The rules for ++ say that, with ptr++, the resulting value is that of ptr when the operation starts and, separately, the value of ptr is incremented. The actual increment of ptr in memory may occur before, during, or after the production of the result value, but it does not affect the value: The value produced is always the value of ptr before the increment, regardless of when the increment actually occurs.
The rules for * say the result is the object that its operand points to. So, with *ptr++, the result is the object that ptr points to before the increment is applied.
Each expression if it is not a void expression has a value.
The value of the postfix increment is the value of its operand before incrementing.
From the C Standard (6.5.2.4 Postfix increment and decrement operators)
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)
That is this expression
*ptr++
is evaluated like
*( ptr++ )
and the value of the expression in the parentheses is the value of the pointer (the operand of the postfix increment) before incrementing of the operand itself that is evaluated as a side effect.
This is the difference between the postfix increment and the prefix increment for which (6.5.3.1 Prefix increment and decrement operators)
2 The value of the operand of the prefix ++ operator is incremented.
The result is the new value of the operand after incrementation.
It is useful to know that the postfix increment operator may be used to form a subscript expression while the prefix increment operator may not.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
int a[] = { 1, 2 };
int *p = &a[0];
printf( "a[0] = %d, a[1] = %d\n", a[0], a[1] );
p++[0] = 3;
*p = 4;
printf( "a[0] = %d, a[1] = %d\n", a[0], a[1] );
return 0;
}
The program output is
a[0] = 1, a[1] = 2
a[0] = 3, a[1] = 4
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.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 5 years ago.
Are postfix increment/decrement operators evaluated after the expression is evaluated or after the entire statement is evaluated ?
#include<stdio.h>
void main()
{
int a=0;
int b=0;
printf("%d %d",a||b,b++); // Output is 1 0
}
My compiler evaluates the printf arguments from right to left. The answer of expression a||b is 1, it means that b has incremented before a||b has been evaluated(i.e b is incremented immediately after evaluating the expression b++)
I read here Incrementing in C++ - When to use x++ or ++x? that postfix increment/decrement are evaluated after the entire statement.
Which is correct?
The order of evaluations of function arguments is unspecified. All side effects related to the argument evaluations are applied before the control will be passed to the called function.
From the C Standard (6.5.2.2 Function calls)
10 There is a sequence point after the evaluations of the function
designator and the actual arguments but before the actual call.
Here is a demonstrative program
#include <stdio.h>
struct
{
int x;
} a = { 0 };
void f( int x )
{
printf( "x = %d\n", x );
printf( "a.x = %d\n", a.x );
}
int main(void)
{
f( a.x++ );
}
Its output is
x = 0
a.x = 1
Due to the side effect in this call then one argument is dependent on a side effect of other argument and the evaluation of the side effect indeterminately sequenced relative the arguments
printf("%d %d",a||b,b++);
the program has undefined behavior.
There are four operators in C when side effects are sequenced between operand evaluations. They are the logical AND operator (&&), logical OR operator (||)comma operator (,), and the conditional operator ( ?:).
For example
#include <stdio.h>
int main(void)
{
int x = 0;
printf( "x = %d\n", x++ == 0 ? x : x - 1 );
}
The program output is
x = 1
The side effect of the evaluation of the expression x++ was sequenced before the evaluation the expression x after the ? sign.
The top answer of the question you linked to is inaccurate. The increment in x++ is only guaranteed to happen after determining the value of the expression, and sometimes before evaluating a containing expression, but there are no other guarantees on when it happens.
In particular, since side effects of arguments to the same function call are indeterminately sequenced, that program has undefined behavior.
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.
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;