int i = 0;
void f() { ++i; }
void (*a[])() = { f, f, f, f, f };
int main() { a[++i](); }
As this is pure C I wonder if there is anything in the C Standard to
prohibit this sequence of evaluations of the statement in main:
evaluate the arguments (trivial in this case)
sequence point
evaluate a[++i] to determine which function pointer
call the function through the pointer
execute the function
Francis
I think C99 6.5.2.2p10 is intended to prohibit that sequence:
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.
even if a literal reading of it might say the sequence is permitted.
Seems that clarification is necessary.
--
Jun, Woong (woong.jun at gmail.com)
> The following code has just been posted to comp.std.c++
> In the following code, can it be shown by reference to
> the standard that there is a sequence point between the
> 'a[++i]' used to call 'f' and the '++i' in f?
>
> int i = 0;
> void f() { ++i; }
> void (*a[])() = { f, f, f, f, f };
> int main() { a[++i](); }
It seems pretty clear from 6.5.2.2p10 (in n1256):
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.
The function designator is evaluated, then there is a
sequence point just before the function call. Hence
the ++i in a[++i] must be completed before actually
calling the function.
> As this is pure C I wonder if there is anything in the C Standard to
> prohibit this sequence of evaluations of the statement in main:
>
>
> evaluate the arguments (trivial in this case)
> sequence point
> evaluate a[++i] to determine which function pointer
> call the function through the pointer
> execute the function
There has to be a sequence point after evaluating the
function designator and before calling the function.
Otherwise the same reasoning could be applied to
function arguments, since arguments and the function
designatore are treated symmetrically in the text
of 6.5.2.2p10.
The text of n1336 clarifies this point, in case
someone is interested. I don't have the text
handy but here's the link:
On the contrary, that paragraph states very clearly that Francis's code
snippet is valid and its semantics well-defined. There is a sequence
point between a[++i] and ().
This, on the other hand, is *not* well-defined:
int i = 0;
void f0(int j) { i += j * 0; }
void f1(int j) { i += j * 1; }
void f2(int j) { i += j * 2; }
void f3(int j) { i += j * 3; }
void f4(int j) { i += j * 4; }
void (*a[])() = { f0, f1, f2, f3, f4 };
int main() { a[++i](++i); }
There is a sequence point before the actual call, but not (IIUC) between
the evaluation of the function designator (here, a[++i]) and that of the
actual arguments (here, ++i), so the code in main() invokes undefined
behavior.
DES
--
Dag-Erling Smørgrav - d...@des.no
I think that the clear meaning of that statement is that all of
evaluations it mentions occur before the sequence point; if it doesn't
mean that, then the sequence point is meaningless.
> Francis Glassborow <francis.glassbo...@btinternet.com> wrote:
> > As this is pure C I wonder if there is anything in the C Standard to
> > prohibit this sequence of evaluations of the statement in main:
> >
> > evaluate the arguments (trivial in this case)
> > sequence point
> > evaluate a[++i] to determine which function pointer
> > call the function through the pointer
> > execute the function
>
> I think C99 6.5.2.2p10 is intended to prohibit that sequence:
>
> 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.
>
> even if a literal reading of it might say the sequence is permitted.
> Seems that clarification is necessary.
I wouldn't call it _necessary_, really, since it is plain what is meant.
However, since a new Standard is being worked on anyway, it should be
relatively simple to add clarification, especially as it would not need
to exist of anything more than the word "just".
Richard
I agree that the intent of the paragraph is clear, but I don't think
a literal reading conveys the intent clearly.
> that Francis's code
> snippet is valid and its semantics well-defined. There is a sequence
> point between a[++i] and ().
I assume you meant a function call by "()," not evaluation of
arguments. On the contrary, a literal reading says an implementation
need not put a sequence point between a[++i] and () as long as it did
before (). 3:59PM is before 4PM, and so is 2PM.
The committee seemed to also think it necessary; as Tim Rentsch
quoted in his post, the current draft of C1x contains wording
clarified. I agree the word "just" would be enough, but they
elaborated much more.
Besides, even if the committee confirmed in a C90 DR that specifying
statements should be executed in sequence prevented executions of two
or more functions from being interleaved, they made it explicit in
the draft; I think that's a good change.
I'm trying to read these comments in a positive light,
but I'm really having trouble with that. The standard
is written in English. The sentence construction here
makes it clear that a sequence point separates the
evaluation of all the operands (including the function
designator) and the operation of function call. The
word "literal" doesn't mean "deliberately stupid."
You are focusing on just one word, the word "before".
However that word appears in a context where it
obviously relates one item to other items mentioned
in the same context.
> ralt...@xs4all.nl (Richard Bos) wrote:
> [...]
>>
>> I wouldn't call it _necessary_, really, since it is plain what is meant.
>> However, since a new Standard is being worked on anyway, it should be
>> relatively simple to add clarification, especially as it would not need
>> to exist of anything more than the word "just".
>>
>
> The committee seemed to also think it necessary; as Tim Rentsch
> quoted in his post, the current draft of C1x contains wording
> clarified. I agree the word "just" would be enough, but they
> elaborated much more.
The wording was changed, but I attribute that to the
complete revision of all portions of the Standard
regarding sequencing, in support of the new sequencing
model. The meaning of the old wording was clear,
it's just being expressed in the language of the
new model.
Since I was not following up what happens in revising the standard, I
missed a new sequencing model had been introduced. The change to the
old wording does not necessarily mean that the committee thought it
needed clarification.
I've never thought that the reading I said above was reasonable. If
the sequence point in question could be put before evaluating a
function designator rather than before function call, nothing would
prevent it from being put before evaluating arguments, which would
completely make the whole sentence meaningless.
I was explaining to Dag-Erling Smørgrav the "literal" (or
"deliberately stupid," if you like) way to read the standard in which
a reader could get a twisted interpretation. And I think it is worth
while to clarify it if a simple change like adding "just" effectively
preclude such a reading; there is a similar (and more serious as I
recall) problem in C99 that is related to the word "after."
I think you are mixing syntax and semantics with the execution model.
The () operator evaluates to the function call designator and has two
operands,
the second of which is possibly empty. 6.5.2.2/4 makes it clear that
this
operators expression is fully evaluated before the call is made. The
key point
is that the parentheses in the expression have no meaning for the
execution
sequence but are an unusual form to write an operator. And you
wouldn't
demand s.g. like 'a +' to yield anything in C, why then for the
function call
operator?
regards,
Mark
Nobody (nethier Dag-Erling Smørgrav who fisrt used "()" to mean
function call nor me) did (or at least nobody did to make others
confused). As you said, "()" is a function call operator that
evaluates its operands and performs call to the designated function.
Reading in context, however, it was clear that the notation "()" was
used to mean "function call" in the discussion. Furthermore, I
declared explicitly to use it so as presumedly Dag-Erling Smørgrav
did in his post.
[...]
> The
> key point
> is that the parentheses in the expression have no meaning for the
> execution
> sequence but are an unusual form to write an operator. And you
> wouldn't
> demand s.g. like 'a +' to yield anything in C, why then for the
> function call
> operator?
>
What makes you think somebody else said different things?
I cite you again:
> > On 21 Okt., 03:28, Jun Woong <wo...@icu.ac.kr> wrote:
> > > I assume you meant a function call by "()," not evaluation of
> > > arguments. On the contrary, a literal reading says an implementation
> > > need not put a sequence point between a[++i] and () as long as it did
> > > before (). 3:59PM is before 4PM, and so is 2PM.
> [...]
The "a sequence point between a[++i] and ()" phrase hints towards a
confusion of syntax with execution model IMHO (maybe not from your
side, but I lost track during the discussion). As a[++i] is one of the
arguments of the () operator, it makes no sense to say "between".
There is equally no "between" in a half-spelled addition, as I tried
to expose.
regards,
Mark
> The "a sequence point between a[++i] and ()" phrase hints towards a
> confusion of syntax with execution model IMHO (maybe not from your
> side, but I lost track during the discussion). As a[++i] is one of the
> arguments of the () operator,
No it isn't, at best, a[++i} is one of the operands of the () operator.
The other operand is the argument list.
it makes no sense to say "between".
> There is equally no "between" in a half-spelled addition, as I tried
> to expose.
consider:
int main(){
int i = 0;
int j = 0;
int k;
k = (i++, i++) + (j++, j++); // OK, well defined
k = (i++, j++) + (i++, j++); // UB
}
Not quite what you meant, but I am trying to illustrate that sequence
points by themselves are not enough. In the case of the function call we
simply need a guarantee that there is a sequence point IMMEDIATELY
before the actual call.
I do not think that C90 provided that guarantee. I am not certain that
C99 does. We have the opportunity to ensure that C1x does but should not
spend too much time on it because in the real world it is a non issue
except where the guarantee is necessary for safety critical work.
Aehem...care to explain? The subtle winged bracket?
> The other operand is the argument list.
> it makes no sense to say "between".
>
> > There is equally no "between" in a half-spelled addition, as I tried
> > to expose.
>
> consider:
>
> int main(){
> int i = 0;
> int j = 0;
> int k;
> k = (i++, i++) + (j++, j++); // OK, well defined
> k = (i++, j++) + (i++, j++); // UB
>
> }
>
> Not quite what you meant, but I am trying to illustrate that sequence
> points by themselves are not enough. In the case of the function call we
> simply need a guarantee that there is a sequence point IMMEDIATELY
> before the actual call.
>
> I do not think that C90 provided that guarantee. I am not certain that
> C99 does. We have the opportunity to ensure that C1x does but should not
> spend too much time on it because in the real world it is a non issue
> except where the guarantee is necessary for safety critical work.
Ok, I see now that this comes from the sloppy verbiage in 6.5.2.2/10
("but there is a sequence point before the actual call"). The only
thing I can argue in favor of the Standard is that as the operands to
the () can have arbitrary sequence points in themselves, it would be
nonsensical to read it in any other than the intended way. But yes, it
is not explicit enough, I see that now.
regards,
Mark