Is the semicolon really a sequence point in C? - 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.

Related

In place vector "abs" warning: operation may be undefined? [duplicate]

A sequence point in imperative programming defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.
What does this mean? Can somebody please explain it in simple words?
When a sequence point occurs, it basically means that you are guaranteed that all previous operations are complete.
Changing a variable twice without an intervening sequence point is one example of undefined behaviour.
For example, i = i++; is undefined because there's no sequence point between the two changes to i.
Note that it's not just changing a variable twice that can cause a problem. It's actually a change involved with any other use. The standard uses the term "value computation and side effect" when discussing how things are sequenced. For example, in the expression a = i + i++, the i (value computation) and i++ (side effect) may be done in arbitrary order.
Wikipedia has a list of the sequence points in the C and C++ standards although the definitive list should always be taken from the ISO standard. From C11 appendix C (paraphrased):
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.
An important thing to note about sequence points is that they are not global, but rather should be regarded as a set of local constraints. For example, in the statement
a = f1(x++) + f2(y++);
There is a sequence point between the evaluation of x++ and the call to f1, and another sequence point between the evaluation of y++ and the call to f2. There is, however, no guarantee as to whether x will be incremented before or after f2 is called, nor whether y will be incremented before or after x is called. If f1 changes y or f2 changes x, the results will be undefined (it would be legitimate for the compiler's generated code to e.g. read x and y, increment x, call f1, check y against the previously-read value, and--if it changed--go on a rampage seeking out and destroying all Barney videos and merchandise; I don't think any real compilers generate code that would actually do that, alas, but it would be permitted under the standard).
Expanding on paxdiablo's answer with an example.
Assume the statement
x = i++ * ++j;
There are three side effects: assigning the result of i * (j+1) to x, adding 1 to i, and adding 1 to j. The order in which the side effects are applied is unspecified; i and j may each be incremented immediately after being evaluated, or they may not be incremented until after both have been evaluated but before x has been assigned, or they may not be incremented until after x has been assigned.
The sequence point is the point where all side effects have been applied (x, i, and j have all been updated), regardless of the order in which they were applied.
It means a compiler may do funky optimizations, tricks and magic but must reach a well-defined state at these so-called sequence points.

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.

Assignment operator and side effects with sequence points

I'm looking for some clarification for the emphasised line.
(C99 6.5.16/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, but is not an lvalue. The
type of an assignment expression is the type of the left operand
unless the left operand has qualified type, in which case it is the
unqualified version of the type of the left operand. The side effect
of updating the stored value of the left operand shall occur between
the previous and the next sequence point.
Consider the following example:
int x = 42;
int y = 0;
int main()
{
// side effect of modifying 'x'
x = y;
}
What are the previous and next sequence point? Is there a sequence point at the start of main?
C99 5.1.2.3 defines sequence points as the places by which all side effects of the previous evaluations have taken place and the side effect of subsequent evaluations have not yet started taking place. The annex C of the standard defines the places where the sequence points take place: function calls, end of logical operators, the comma operator, and the ternary operator, end of a full declarations, end of a full expression, and so on.
In this case, the previous sequence point is the start of main(), and the next sequence point is the semicolon at the end of the assignment. At the first sequence point, x will have a value of 42, and at the second one, it will be 0.
Here is an explanation about sequence points from the C FAQ.
In this case, the sequence points are just before and after the full expression x = y;.
Just to add to user4815162342's answer, too long for a comment. Statements are sequenced:
A statement specifies an action to be performed. Except as indicated,
statements are executed in sequence.
So as a rule of thumb you have a sequence point at every ;, though they are not mentioned explicitly as such in the standard.

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).

sequence points in c

A sequence point in imperative programming defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.
What does this mean? Can somebody please explain it in simple words?
When a sequence point occurs, it basically means that you are guaranteed that all previous operations are complete.
Changing a variable twice without an intervening sequence point is one example of undefined behaviour.
For example, i = i++; is undefined because there's no sequence point between the two changes to i.
Note that it's not just changing a variable twice that can cause a problem. It's actually a change involved with any other use. The standard uses the term "value computation and side effect" when discussing how things are sequenced. For example, in the expression a = i + i++, the i (value computation) and i++ (side effect) may be done in arbitrary order.
Wikipedia has a list of the sequence points in the C and C++ standards although the definitive list should always be taken from the ISO standard. From C11 appendix C (paraphrased):
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.
An important thing to note about sequence points is that they are not global, but rather should be regarded as a set of local constraints. For example, in the statement
a = f1(x++) + f2(y++);
There is a sequence point between the evaluation of x++ and the call to f1, and another sequence point between the evaluation of y++ and the call to f2. There is, however, no guarantee as to whether x will be incremented before or after f2 is called, nor whether y will be incremented before or after x is called. If f1 changes y or f2 changes x, the results will be undefined (it would be legitimate for the compiler's generated code to e.g. read x and y, increment x, call f1, check y against the previously-read value, and--if it changed--go on a rampage seeking out and destroying all Barney videos and merchandise; I don't think any real compilers generate code that would actually do that, alas, but it would be permitted under the standard).
Expanding on paxdiablo's answer with an example.
Assume the statement
x = i++ * ++j;
There are three side effects: assigning the result of i * (j+1) to x, adding 1 to i, and adding 1 to j. The order in which the side effects are applied is unspecified; i and j may each be incremented immediately after being evaluated, or they may not be incremented until after both have been evaluated but before x has been assigned, or they may not be incremented until after x has been assigned.
The sequence point is the point where all side effects have been applied (x, i, and j have all been updated), regardless of the order in which they were applied.
It means a compiler may do funky optimizations, tricks and magic but must reach a well-defined state at these so-called sequence points.

Resources