x=(x=5,11)

G

Guest

Old said:
It isn't. A side-effect is part of an expression evaluation.
It may occur before or after (or at the same time as) the
value of the expression is computed.

(The point I'm making else-thread is that the side-effect
"obviously" cannot occur before the right-hand operand
has been evaluated.)


I don't see where he is saying that.


Naturally. a's side effects must complete before b is evaluated,
and c's side effects must complete before d is evaluated; there
is no other constraint.

Even though with the given ordering, the next sequence point after the
evaluation of b is that of the comma operator separating c and d ?

If that's how you feel, then I don't see how you can claim the
evaluation of the outer = operator in x=(x=5,11) can't start before the
operands have been fully evaluated. "Obviously" doesn't apply, since a
possible way has been given in other messages already.
 
O

Old Wolf

Harald said:
Even though with the given ordering, the next sequence point after the
evaluation of b is that of the comma operator separating c and d ?

The sequence points could occur in either order, because the
order of evaluation of the operands of (+) is unspecified.
If that's how you feel, then I don't see how you can claim the
evaluation of the outer = operator in x=(x=5,11) can't start before the
operands have been fully evaluated.

I'm claiming that the side-effect of the outer = cannot occur
until the operands have been fully evaluated (with side-effects
of those evaluations not necessarily complete).
 
G

Guest

Old said:
The sequence points could occur in either order, because the
order of evaluation of the operands of (+) is unspecified.

You snipped the relevant sentence:

"if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed."

This evaluation order is not at all required, but *IF* this is the one
that's used, does your view change any?
 
E

ena8t8si

Tim said:
On 29 May 2006 06:32:10 -0700,


Now we're getting somewhere.

"(and after the assignment operator has been evaluated)"

Where is this in the standard?

"Evaluation of an expression may produce side effects."
Obviously if evaluation produces the side effects, then
the side effects can't come first.
(a,b) + (c,d)

if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed.

I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.
 
G

google

"Evaluation of an expression may produce side effects."
Obviously if evaluation produces the side effects, then
the side effects can't come first.

But they can come during.
I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.

So does this have undefined behaviour, or implementation defined
behaviour?

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}


FYI:
$ gcc -W -Wall -ansi -pedantic -O2 -o test test.c
$ ./test
1
$

Despite gcc doing a then b then c then d, I'm saying that this is
undefined behaviour because the sequence point at the second comma does
not limit when the side effects of b can occur and so can overlap with
the side effects of d.

Tim.
 
O

Old Wolf

Harald said:
You snipped the relevant sentence:

Sorry -- I misread
"if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed."

Yes: if b is evaluated before c, then b's side effect must complete
before d is evaluated.
This evaluation order is not at all required, but *IF* this is the one
that's used, does your view change any?

No. This doesn't exclude the possibility:
- evaluate a
- evaluate c
- evaluate d
- evaluate b
- b's side effect
- d's side effect
 
D

Dave Thompson

On 29 May 2006 07:14:23 -0700, (e-mail address removed) wrote:
Incidentally, there is, I think, an appendix "Formal model of sequence
points" http://www.davros.org/c/wg14n822.txt
(http://www.davros.org/c/wg14papers.html - informative, not normative)
which I _think_ would agree that x=(x=5,11); is defined.
Several versions of a formal model were attempted during the C99
process, but apparently none of them got enough support to be adopted.

- David.Thompson1 at worldnet.att.net
 
E

ena8t8si

But they can come during.

Evaluation of operators are point events. See Wojtek's
explanation in comp.std.c.
I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.

So does this have undefined behaviour, or implementation defined
behaviour?

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}

Undefined behavior.
FYI:
$ gcc -W -Wall -ansi -pedantic -O2 -o test test.c
$ ./test
1
$

Despite gcc doing a then b then c then d, I'm saying that this is
undefined behaviour because the sequence point at the second comma does
not limit when the side effects of b can occur and so can overlap with
the side effects of d.

Correct.
 
E

ena8t8si

Old said:
Sorry -- I misread


Yes: if b is evaluated before c, then b's side effect must complete
before d is evaluated.

Sorry, that isn't right. The terms "previous sequence point"
and "next sequence point" are to be read as a logical relationship
based on the abstract syntax tree, not a temporal relationship
based on any particular execution order.
 
G

Guest

Sorry, that isn't right. The terms "previous sequence point"
and "next sequence point" are to be read as a logical relationship
based on the abstract syntax tree, not a temporal relationship
based on any particular execution order.

So you keep asserting, even though it is clear there is disagreement
and the standard is unclear about it.
 
B

Barry Schwarz

But they can come during.

Evaluation of operators are point events. See Wojtek's
explanation in comp.std.c.
(a,b) + (c,d)

if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed.

I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.

So does this have undefined behaviour, or implementation defined
behaviour?

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}

Undefined behavior.

Since there are sequence points before each function call to f, why do
you think this is any worse than implementation defined behavior.

While the comment is true, the conclusion is not. It is not the comma
operators that limit the side effects but the sequence points before
the function calls.


Remove del for email
 
E

ena8t8si

Harald said:
So you keep asserting, even though it is clear there is disagreement
and the standard is unclear about it.

My comment is meant to be read as an explanation, not
an assertion.

However, since you're interested, read the response
to Clive Feather's DR 087, on order of evaluation.
 
E

ena8t8si

Barry said:
(e-mail address removed) wrote:
Tim Woodall wrote:
On 29 May 2006 06:32:10 -0700,

Of course not. The order of evaluation of the operators
doesn't determine the order in which the side effects
take place. Evaluating an assignment operator causes
a store to take place, but the side effect of updating the
stored value may take place at any point before the
next sequence point (and after the assignment operator
has been evaluated).


Now we're getting somewhere.

"(and after the assignment operator has been evaluated)"

Where is this in the standard?

"Evaluation of an expression may produce side effects."
Obviously if evaluation produces the side effects, then
the side effects can't come first.

But they can come during.

Evaluation of operators are point events. See Wojtek's
explanation in comp.std.c.
(a,b) + (c,d)

if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed.

I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.

So does this have undefined behaviour, or implementation defined
behaviour?

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}

Undefined behavior.

Since there are sequence points before each function call to f, why do
you think this is any worse than implementation defined behavior.

The object d[1] can be updated more than once after all
the calls to f have completed.
While the comment is true, the conclusion is not. It is not the comma
operators that limit the side effects but the sequence points before
the function calls.

The sequence points before the function calls don't change
anything. The function calls have to complete before the side
effects in each case, but the side effects of (*f(1))++ and
(*f(3))++ can still overlap each other. The expression

((*f(0))++, p=f(1), (*p)++) + ((*f(2))++, q=f(3), (*q)++)

also has undefined behavior, for the same reason.
 
G

Guest

My comment is meant to be read as an explanation, not
an assertion.

However, since you're interested, read the response
to Clive Feather's DR 087, on order of evaluation.

http://open-std.org/JTC1/SC22/WG14/www/docs/dr_087.html

Thanks. Using your interpretation of sequence points, which is the
intervening sequence point between the two assignments to g in line B?
With "previous" and "next" sequence point referring to the previous and
next in time, the expression is unspecified but not undefined with any
order of evaluation, but using your interpretation, I think the
behaviour would be undefined (and the answer is that it is not
undefined).
 
G

google

Barry said:
(e-mail address removed) wrote:

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}

Undefined behavior.

Since there are sequence points before each function call to f, why do
you think this is any worse than implementation defined behavior.

The object d[1] can be updated more than once after all
the calls to f have completed.

I don't understand your reasoning here!

In x=(x=5,11);

I am saying that both updates of the x can start at the beginning of
the statement. The x=5 has to complete by the comma and the x=11 has to
complete at the semicolon. Hence there is a period where two updates
can be affecting the same variable at the same time.

You seem to think that the comma operator puts a limit on when the x=11
can _start_.

(fair enough - I actually think this was the intent of the standard
authors otherwise things like g=f(); where g is global and f updates it
can have unexpected results - but I think a "legal" interpretation of
the standard would allow my "clear before write" "optimization" even if
no compiler writer would actually take advantage of it)

But in my example above either d[1] gets updated exactly once or there
_must_ be an sequence point between the two updates. In this instance
you seem to have chosen my interpretation of previous and next sequence
point where a sequence point that occurs in time between two other
sequence points is not necessarily previous to one and after the other.

((*f(0))++, p=f(1), (*p)++) + ((*f(2))++, q=f(3), (*q)++)

also has undefined behavior, for the same reason.

This is completely different. If you think this is even remotely the
same as my example then you haven't understood the subtleties of my
code. Its obvious that there doesn't have to be _any_ sequence point
between the (*p)++ and the (*q)++ regardless of the evaluation order.

I had thought that we had at least got to the point where if there are
three sequence points S(0) < S(1) < S(2) (where < denotes a time
ordering) then we were debating whether the standard states that S(1)
is the next sequence point to S(0) and the previous sequence point to
S(2) but now I'm not sure what you are arguing.

If you can convince me that the standard does say this then I accept
that x=(x=5,11) has defined behaviour, as does my example above[1]. But
your "((*f(0))++, p=f(1), (*p)++) + ((*f(2))++, q=f(3), (*q)++)" still
has undefined behaviour.

Tim.

[1] defined here means my code can output 0 or 1 but nothing else.
 
T

Tim Woodall

This is completely different. If you think this is even remotely the
same as my example then you haven't understood the subtleties of my
code. Its obvious that there doesn't have to be _any_ sequence point
between the (*p)++ and the (*q)++ regardless of the evaluation order.
No. I'm wrong here. my example does always have undefined behaviour and
your example is the same.

However, we have agreed something from this (quick bit of face saving :)

The evaluation of the left and right operands of a binary operator can
overlap.

Therefore I still contend that the writing to x=() in the subject can
overlap with the evaluation of (x=5,11), even if the final value cannot
be written until x=5 has completed.

Tim.
 
T

Tim Woodall

How about?


#include <stdio.h>

unsigned int* f(int x)
{
static unsigned int d[2];
static unsigned int done[2];

done[x] = 1;

if(done[0] && d[0])
return &d[0];
else
return &d[1];
}

int main(void)
{
printf("%u\n", (*f(0))-- + (*f(1))++ );
return 0;
}

Tim.
 
B

Barry Schwarz

Barry said:
(e-mail address removed) wrote:
(e-mail address removed) wrote:
Tim Woodall wrote:
On 29 May 2006 06:32:10 -0700,

Of course not. The order of evaluation of the operators
doesn't determine the order in which the side effects
take place. Evaluating an assignment operator causes
a store to take place, but the side effect of updating the
stored value may take place at any point before the
next sequence point (and after the assignment operator
has been evaluated).


Now we're getting somewhere.

"(and after the assignment operator has been evaluated)"

Where is this in the standard?

"Evaluation of an expression may produce side effects."
Obviously if evaluation produces the side effects, then
the side effects can't come first.

But they can come during.

Evaluation of operators are point events. See Wojtek's
explanation in comp.std.c.

(a,b) + (c,d)

if an example implementation evaluates a then b then c then d then you
seem to be saying that the sequence point after c but before d means
that all the side effects of evaluating b will have completed.

I'm not. Both commas must be evaluated before plus. There is
no ordering between either operand of the first comma and
either operand of the second comma. When the Standard says
"the next sequence point" what it means is the first sequence
point that must come afterwards in all possible orderings. The
next sequence point after b is the sequence point of the whole
expression, regardless of evaluation order.

So does this have undefined behaviour, or implementation defined
behaviour?

#include <stdio.h>

int* f(int x)
{
static int d[4];
static int done[4];
static int twice;
done[x]=1;
if(x==2 && done[0] && done[1])
twice=1;
if(x==3 && twice)
return &d[1];
else
return &d[x];
}

int main(void)
{
printf("%d\n", ( (*f(0))++, (*f(1))++ ) + ( (*f(2))++, (*f(3))++ )
);
return 0;
}

Undefined behavior.

Since there are sequence points before each function call to f, why do
you think this is any worse than implementation defined behavior.

The object d[1] can be updated more than once after all
the calls to f have completed.

I don't see how. The only way d[1] can be updated is if f() returns
its address. The expression f(1) will always return &d[1]. The
expression f(3) will return &d1 if twice is not 0. No other call to
f() will return &d[1].

Let us assume that twice is not 0 by the time f(3) is evaluated
(otherwise d1 is updated only once and we have no multiple updates at
all). The two possibilities are:

f(1) is evaluated before f(3). f(1) returns &d1. The
evaluation of f(3) obviously involves a call to the function f. There
is a sequence point before this call. That means that any side
effects of (*f(1))++ must be complete before this call. The side
effect is the update to d[1] and it is completed before the call.
Sometime after the return from f(3), d[1] is updated again but there
was a sequence point between this update and the previous one.

f(3) is evaluated before f(1). The argument is symmetrical.

The bottom line is that at each call to f, all updates to d have been
completed. After the last call to f, there is only one update to be
performed.
The sequence points before the function calls don't change
anything. The function calls have to complete before the side
effects in each case, but the side effects of (*f(1))++ and
(*f(3))++ can still overlap each other. The expression

Since f(1) cannot overlap f(3) and since there is a sequence point
between the end of one call and the start of the next, whichever
expression is evaluated first must complete its side effect before the
next function call.
((*f(0))++, p=f(1), (*p)++) + ((*f(2))++, q=f(3), (*q)++)

also has undefined behavior, for the same reason.

But this is different. (*p)++ does not involve a function call and
there is no guaranteed sequence point between (*p)++ and (*q)++. The
sequence of evaluation could be
(*f(0))++
p = f(1)
(*f(2))++
q = f(3)
(*p)++
(*q)++
sum
and the penultimate two steps do in fact both update d[1] (if twice is
not 0) with no intervening sequence point.


Remove del for email
 
G

google

Barry Schwarz wrote:

<snip and summarize thus>

((*f(0))++, (*f(1))++) + ((*f(2))++, (*f(3))++)

(we're assuming here that f(0) is done before f(1) is done before f(2)
is done before f(3) - other orderings are allowed but are not relevant
to this discussion. f(3) returns a pointer to the same address as f(1))
I don't see how. The only way d[1] can be updated is if f() returns
its address. The expression f(1) will always return &d[1]. The
expression f(3) will return &d1 if twice is not 0. No other call to
f() will return &d[1].
(I'm using some lazy shorthand here - f(0)++ actually means (*f(0))++
etc)

because f(0) is done before f(1) and there is a comma sequence point
after f(0) and before f(1) the side effects of the f(0)++ must be
completed before f(1).

because f(2) is done before f(3) and there is a comma sequence point
after f(2)++ and before f(3) the side effects of the f(2)++ must be
completed before f(3).

But f(1) can be called before f(2) but the increment deferred until the
end of the full expression. What this does mean is that part of f(1)++
is evaluated before the various sequence points on the RHS of the +
operator and part of it is evaluated after, i.e. the evaluation of the
f(1)++ sub expression crosses sequence points.


What we are really interested in is whether the standard allows the
increment of f(1)++ to start before f(2) is called but to not complete
until the end of the full expression.


consider g++ + f(); and (g=g+1) + f(); and (g=5) + f(); where f()
modifies g. Do these have defined or undefined behaviour?

f(1) is evaluated before f(3). f(1) returns &d1. The
evaluation of f(3) obviously involves a call to the function f. There
is a sequence point before this call. That means that any side
effects of (*f(1))++ must be complete before this call. The side
The side effects of (*f(1))++ do not have to have started by the time
of the call to f(3).

Tim.
 
B

Barry Schwarz

Barry Schwarz wrote:

<snip and summarize thus>

((*f(0))++, (*f(1))++) + ((*f(2))++, (*f(3))++)

(we're assuming here that f(0) is done before f(1) is done before f(2)
is done before f(3) - other orderings are allowed but are not relevant
to this discussion. f(3) returns a pointer to the same address as f(1))
I don't see how. The only way d[1] can be updated is if f() returns
its address. The expression f(1) will always return &d[1]. The
expression f(3) will return &d1 if twice is not 0. No other call to
f() will return &d[1].
(I'm using some lazy shorthand here - f(0)++ actually means (*f(0))++
etc)

because f(0) is done before f(1) and there is a comma sequence point
after f(0) and before f(1) the side effects of the f(0)++ must be
completed before f(1).

While the comma sequence point does in fact guarantee this, the
sequence point before the call to f(1) also guarantees it. It doesn't
matter why there is a sequence point, only that there is one.
because f(2) is done before f(3) and there is a comma sequence point
after f(2)++ and before f(3) the side effects of the f(2)++ must be
completed before f(3).

As I said in the portion you chose to snip, neither f(0) nor f(2)
matter since they cannot have any effect of d[1].
But f(1) can be called before f(2) but the increment deferred until the
end of the full expression. What this does mean is that part of f(1)++

No it cannot. There is a sequence point prior to the call to f(2) and
any side effect from f(1) must be completed before this sequence
point.
is evaluated before the various sequence points on the RHS of the +
operator and part of it is evaluated after, i.e. the evaluation of the
f(1)++ sub expression crosses sequence points.

Evaluations never cross sequence points. The whole purpose of
sequence points is to insure that the evaluation is complete.
What we are really interested in is whether the standard allows the
increment of f(1)++ to start before f(2) is called but to not complete
until the end of the full expression.

The standard guarantees that all side effects are complete prior to
the sequence point. Since there is a sequence point prior to the call
to f(2), the increment must be complete.
consider g++ + f(); and (g=g+1) + f(); and (g=5) + f(); where f()
modifies g. Do these have defined or undefined behaviour?

Since evaluating g in its many forms does not involve a sequence
point, this is nothing but a red herring.
The side effects of (*f(1))++ do not have to have started by the time
of the call to f(3).

How can you state that when the standard guarantees exactly the
opposite? There is a sequence point before the call to f(3) and side
effects must be complete at the sequence point.


Remove del for email
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,978
Members
47,561
Latest member
gjsign

Latest Threads

Top