Is the behaviour of following expression well defined? - c

Cosider the sequence points in the following expression
i = (++i,i++,i);
If I am correct the steps of execution will be as follows:
1)
++i, i++
2)
step1,i
3)
i = step2
For evaluation in step 1, the value of i should be modified only once for the construct to be termed as defined(since after evaluation of comma operator there is a sequence point). But I think it is not the case here. Hence it should be undefined.
Please see this answer. Here the above expression is termed as defined. Am I missing something ?

The behavior of the following instruction is well-defined.
i = (++i, i++, i);
There is indeed a sequence point between the evaluations of the first and the second operands of the comma operator (,). The annex C of the standard, although informative, provides a description of the sequence points.
C11, Annex C Sequence points
The following are the sequence points described in 5.1.2.3:
— Between the evaluations of the function designator and actual
arguments in a function call and the actual call. (6.5.2.2).
— Between the evaluations of the first and second operands of the following operators: logical AND && (6.5.13); logical OR || (6.5.14);
comma , (6.5.17).
— Between the evaluations of the first operand
of the conditional ? : operator and whichever of the second and third
operands is evaluated (6.5.15). — The end of a full declarator:
declarators (6.7.6);
— Between the evaluation of a full expression and the next full
expression to be evaluated. The following are full expressions: an
initializer that is not part of a compound literal (6.7.9); the
expression in an expression statement (6.8.3); the controlling
expression of a selection statement (if or switch) (6.8.4); the
controlling expression of a while or do statement (6.8.5); each of the
(optional) expressions of a for statement (6.8.5.3); the (optional)
expression in a return statement (6.8.6.4).
— Immediately before a library function returns (7.1.4). — After
the actions associated with each formatted input/output function
conversion specifier (7.21.6, 7.29.2).
— 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 (7.22.5).

Related

Is the semicolon really a sequence point in C?

According to this answer, the following are the sequence points described in the standard:
Between the evaluations of the function designator and actual arguments in a function call and the actual call;
Between the evaluations of the first and second operands of the operators &&, ||, and ,;
Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated;
The end of a full declarator;
Between the evaluation of a full expression and the next full expression to be evaluated. The following are full expressions:
an initializer;
the expression in an expression statement;
the controlling expression of a selection statement (if or switch);
the controlling expression of a while or do statement;
each of the expressions of a for statement;
the expression in a return 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.
The standard never explicitly mentions that the semicolon is a sequence point, but the various sequence points that have been stated kind of imply that the semicolon is indeed a sequence point.
So, is the semicolon in break; or continue; a sequence point?
Is the semicolon really a sequence point in C?
No. Specific semantic language constructs are specifically required to have a sequence point after evaluating them. (like, ex. Logical AND operator ...if the second operand is evaluated, there is a sequence point between... - it's specific). A sequence point is indeed related to, like, semantics ("evaluation of this happens before that") rather than to tokens ("everything happens before the ; character").
So, is the semicolon in break; or continue; a sequence point?
No, it is not. Together with goto they look like a exception to the colloquial rule.
It is not a function call, not a logical operator && ||, not , operator, not a ternary ?: operator, not a declaration, not a full expression - it's not listed in the list you quoted (the list is from ANNEX C), it's not anyhow volatile and does no I/O. So, well, under the "when you have eliminated the impossible, whatever remains, however improbable, must be the truth" logic there is indeed no sequence point after break; nor continue;.
So, is the semicolon in break; or continue; a sequence point?
Better ask yourself, why shouldn't it not be a sequence point?
break and continue are just camouflaged goto, or "jmp".
goto always needs a label, aka a pointer, aka an argument, to be able to jump, same goes for break and continue (these get their label implicit by the surrounding loop).
...
Yes, the semicolon in break; or continue; is a sequence point.

Why does the value of i not increment for i=i++; statement? [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 2 years ago.
Code:
for(int i=0;i<5;){
i=i++;
printf("%d",i);
}
The above program print zeros infinitely, How is that possible?
There is the statement i=i++;. Please explain why the value of i do not increment.
The statement i = i++ is undefined behaviour in C. Simplistically, modifying and using the same object without an intervening sequence point is not guaranteed to work in any way you expect.
Sequence points are covered in Appendix C of the ISO C standard if you're interested in an in-depth investigation. Basically, they consist of:
Between the evaluations of the function designator and actual arguments in a function call and the actual call.
Between the evaluations of the first and second operands of the following operators: logical AND &&; logical OR ||; comma ,.
Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated.
The end of a full declarator.
Between the evaluation of a full expression and the next full expression to be evaluated. The following are full expressions: an initializer that is not part of a compound literal; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the (optional)
expressions of a for statement; the (optional) expression in a return
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.

is this undefined behavior of printf function or not? [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 6 years ago.
int c=2; printf("%d %d %d",c,c<<=2,c>>=2);
Is this undefined behavior ?
int c=2;
printf ("%d %d %d",c,c<<=2,c>>=2);
The behaviour is undefined.
[C99: 4/2]: If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ‘‘behavior that is undefined’’.
[C99: 5.1.2.3/2]: Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (A summary of the sequence points is given in annex C.)
[C99: C/1]: The following are the sequence points described in 5.1.2.3:
- The call to a function, after the arguments have been evaluated (6.5.2.2).
- The end of the first operand of the following operators: logical AND && (6.5.13); logical OR || (6.5.14); conditional ? (6.5.15); comma , (6.5.17).
- The end of a full declarator: declarators (6.7.5);
- The end of a full expression: an initializer (6.7.8); the expression in an expression statement (6.8.3); the controlling expression of a selection statement (if or switch) (6.8.4); the controlling expression of a while or do statement (6.8.5); each of the expressions of a for statement (6.8.5.3); the expression in a return statement (6.8.6.4).
- Immediately before a library function returns (7.1.4).
- After the actions associated with each formatted input/output function conversion specifier (7.19.6, 7.24.2).
- 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 (7.20.5).
[C99: 6.2.2.2/10]: The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
And, although I can't prove a negative, there is no wording to make an exception for the varargs case.

Why doesn’t this code: a[i] = i++; work? [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
a[i] = i++;
Why does the above code not work?
What is wrong with above code? I am asking this question to improve my knowledge.
Because the ISO standard says that you are not allowed to change a variable more than once (or change and use one) without an intervening sequence point.
There is no sequence point between the use of i in a[i] and the change of i in i++.
The list of sequence points from C11 (not really changed that much since C99) are described in Annex C:
Between the evaluations of the function designator and actual arguments in a function call and the actual call.
Between the evaluations of the first and second operands of the following operators: logical AND &&; logical OR ||; comma ,.
Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated.
The end of a full declarator: declarators;
Between the evaluation of a full expression and the next full expression to be evaluated. The following are full expressions: an initializer; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the expressions of a for statement; the expression in a return 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.
and 5.1.2.3 Program execution states:
Evaluations A and B are indeterminately sequenced when A is sequenced either before or after B, but it is unspecified which.
The presence of a sequence point between the evaluation of expressions A and B implies that every value computation and side effect associated with A is sequenced before every value computation and side effect associated with B.
Section 6.5 Expressions pretty much covers your exact case:
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.
This paragraph renders undefined statement expressions such as i = ++i + 1; and a[i++] = i; while allowing i = i + 1; and a[i] = i;.
It does work, but possibly not as expected. The problem is if it's not clear if i gets incremented before the assignment and, if so, then a[i] will reference the next item in the array.
Your question was very terse so you can expand on it if you want more information. But it's just hard to tell exactly which element of a that syntax assigns to.

is i=f(); defined when f modifies i?

Related question: Any good reason why assignment operator isn't a sequence point?
From the comp.lang.c FAQ I would infer that the program below is undefined. Strangely, it only mentions the call to f as a sequence point, between the computation of the arguments and the transfer of control to f. The transfer of control from f back to the calling expression is not listed as a sequence point.
int f(void) { i++; return 42; }
i = f();
Is it really undefined?
As an end-note that I add to many of my questions, I am interested in this in the context of static analysis. I am not writing this myself, I just want to know if I should warn about it in programs written by others.
The transfer of control from f back to
the calling expression is not listed
as a sequence point.
Yes it is.
at the end of the evaluation of a full expression
The complete expression that forms an
expression statement, or one of the
controlling expressions of an if,
switch, while, for, or do/while
statement, or the expression in an
initializer or a return statement.
You have a return statement, therefore, you have a sequence point.
It doesn't even appear that
int f(void) { return i++; } // sequence point here, so I guess we're good
i = f();
is undefined. (Which to me is kind of weird.)
That's not undefined at all. One of the sequence points listed in Appendix C of C99 is the end of a full expression, of which one is the expression in a return statement.
Since you're returning 42, there's a sequence point immediately following that return statement.
For completeness, the C99 sequence points are listed here, with the relevant one bolded:
The following are the sequence points described in 5.1.2.3:
The call to a function, after the arguments have been evaluated (6.5.2.2).
The end of the first operand of the following operators: logical AND && (6.5.13); logical OR || (6.5.14); conditional ? (6.5.15); comma , (6.5.17).
The end of a full declarator: declarators (6.7.5);
The end of a full expression: an initializer (6.7.8); the expression in an expression statement (6.8.3); the controlling expression of a selection statement (if or switch) (6.8.4); the controlling expression of a while or do statement (6.8.5); each of the expressions of a for statement (6.8.5.3); the expression in a return statement (6.8.6.4).
Immediately before a library function returns (7.1.4).
After the actions associated with each formatted input/output function conversion
specifier (7.19.6, 7.24.2).
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 (7.20.5).

Resources