473,480 Members | 2,487 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Multiple Assignment Evaluation Debate

Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits. He
claims it has been a 'C Standard' that it will be evaluted as a = c; b
= c. I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?

Mar 10 '06 #1
77 4641
be***@uwalumni.com said:
Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits. He
claims it has been a 'C Standard' that it will be evaluted as a = c; b
= c. I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?


The associativity is: a = (b = c); but the order of evaluation of a, b, and
c is unspecified. The Standard only requires that the new values of a and b
are provided at some time after the previous, and before the following,
sequence point.

So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
combination that gives the same result.

If you depend on the order of evaluation, any side effects of a, b, and c
are likely to bite you eventually.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Mar 10 '06 #2
On 2006-03-10, be***@uwalumni.com <be***@uwalumni.com> wrote:
Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits.
If you do that, a sprinkling of the "volatile" keyword may do something
for predictability
He claims it has been a 'C Standard' that it will be evaluted as a =
c; b = c.
His interpretaion of the standard is the same as mine.
I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?


Use volatile. You might still get the wrong answer, but it's more likely
to be consistent.
Mar 10 '06 #3

Richard Heathfield wrote:
be***@uwalumni.com said:
Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits. He
claims it has been a 'C Standard' that it will be evaluted as a = c; b
= c. I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?


The associativity is: a = (b = c); but the order of evaluation of a, b, and
c is unspecified. The Standard only requires that the new values of a and b
are provided at some time after the previous, and before the following,
sequence point.

So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
combination that gives the same result.

If you depend on the order of evaluation, any side effects of a, b, and c
are likely to bite you eventually.


You missed the point of his question. Regardless of anything having
to do with evaluation order, the intermediate assignment to b can
affect the value that is assigned to a. int = unsigned char = int,
for example. If b is volatile that may also change the picture,
as another thread discusses. It isn't safe to assume (because
it's open to debate) that a = b = c may be replaced by b = c, a = b
even if b is volatile. But saying a = b = c means (in whatever
order) a = c and b = c is simply wrong.

Mar 10 '06 #4
en******@yahoo.com said:

Richard Heathfield wrote:

If you depend on the order of evaluation, any side effects of a, b, and c
are likely to bite you eventually.


You missed the point of his question. Regardless of anything having
to do with evaluation order, the intermediate assignment to b can
affect the value that is assigned to a.


I invite you to re-read my reply, especially the bit about side effects
(retained above).

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Mar 10 '06 #5

Richard G. Riley wrote:
"en******@yahoo.com"posted the following on 2006-03-10:

Richard Heathfield wrote:
be***@uwalumni.com said:

> Hi All,
>
> A coworker and I have been debating the 'correct' expectation of
> evaluation for the phrase a = b = c. Two different versions of GCC
> ended up compiling this as b = c; a = b and the other ended up
> compiling it as a = c; b = c. (Both with no optimizations enabled).
> How did we notice you may ask? Well, in our case 'b' was a memory
> mapped register that only has a select number of writable bits. He
> claims it has been a 'C Standard' that it will be evaluted as a = c; b
> = c. I personally believe that it would make more sense for it to be
> evaluated as b = c; a = b, although I would never write code that has a
> questionable operation. Can anyone settle this debate?

The associativity is: a = (b = c); but the order of evaluation of a, b, and
c is unspecified. The Standard only requires that the new values of a and b
are provided at some time after the previous, and before the following,
sequence point.

So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
combination that gives the same result.

If you depend on the order of evaluation, any side effects of a, b, and c
are likely to bite you eventually.


You missed the point of his question. Regardless of anything having
to do with evaluation order, the intermediate assignment to b can
affect the value that is assigned to a. int = unsigned char = int,
for example. If b is volatile that may also change the picture,
as another thread discusses. It isn't safe to assume (because
it's open to debate) that a = b = c may be replaced by b = c, a = b
even if b is volatile. But saying a = b = c means (in whatever
order) a = c and b = c is simply wrong.


Why? If you write the code properly and a,b,c are the same types and
none of them are physically volative and this is a single thread app
then I think the code can indeed infer equality. If not then we might
as well give up.

If they are not the same types then without the right casts you have
no right coding like this IMO because of hiccups down the line when
someone less familiar with the code comes along.


Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.

Mar 10 '06 #6
en******@yahoo.com said:
Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.

You are Dan Pop, and I claim my five pounds!
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Mar 10 '06 #7
In article <11*********************@j33g2000cwa.googlegroups. com>
<be***@uwalumni.com> wrote:
A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits. ...
Well, first, if you have not applied the "volatile" qualifier, you
have no right to expect anything in particular, because a compiler
(even without optimization turned on) is allowed to believe that
non-"volatile" objects behave as if they are ordinary RAM. That is,
if you store 3 in some "int", and do not store another value in that
"int", it will still have 3 in it later. So:

void f(void) {
int i = 3;
... /* code that does not modify i */
printf("i is %d\n", i);
...
}

could be compiled to the same object code as:

void f(void) {
... /* code that does not modify i */
puts("i is 3");
...
}

(note the removal of the newline, since puts() adds one; and yes,
gcc really will turn printf() calls into puts() calls in some
cases).
He claims it has been a 'C Standard' that it will be evaluted as a = c; b
= c. I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?


The C89 and C99 standards both use similar (maybe even identical)
wording:

[#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.

The second sentence is particularly important here. It tells us
that, for instance, if we write:

unsigned int a;
unsigned char b;
unsigned int c = 12345;

a = b = c;

the result stored in "a" is almost certainly *not* 12345, as it is
actually (12345 % (UCHAR_MAX + 1)). Typically UCHAR_MAX is 255 so
this is (12345 % 256), or 57. Of course, the compiler can use the
"as-if" rules to compile this as:

a = 57;
b = 57;
c = 12345;

(with the stores to a, b, and c happening in any order in the
actual underlying machine code -- or even being combined, if
there is some quick way to write to two or all three variables).

In the more difficult example where "b" is somehow mapped to a
hardware register, you -- the programmer -- *must* declare b using
the "volatile" qualifier, to tell the compiler "this thing is *not*
ordinary RAM, so you, Mr Compiler, must not play games with
optimizations that assume it *is* ordinary RAM." More typically,
you might replace b with *p where p has type "volatile T *" for
some type T. Consider the example of a memory-mapped device
that has a control-and-status register, in which writes to the
location cause the device to take actions, and reads from the
location return the device's status:

#define CSR_W_DMA 0x01 /* start DMA */
#define CSR_W_LDA 0x02 /* load DMA address from addr reg */
#define CSR_W_EI 0x04 /* enable interrupts */
#define CSR_W_RD 0x08 /* read from device (write to RAM) */
#define CSR_W_WR 0x00 /* write to device (read from RAM) - pseudo */
...
#define CSR_S_DMA 0x01 /* DMA is occuring now */
#define CSR_S_ERR 0x02 /* error occurred doing DMA */
#define CSR_S_IP 0x04 /* interrupt pending / op done-or-failed */
...

volatile int *csr;
volatile int *addr;
...
*addr = dma_addr; /* tell device where to do the op */
*csr = CSR_W_LDA;

/* do read from device, without using interrupts (poll for done) */
*csr = CSR_W_RD | CSR_W_DMA; /* read op with DMA */
while ((*csr & CSR_W_IP) == 0)
continue;

Without the "volatile" qualifier, the compiler can remove the first
write to *csr entirely (because the next write to *csr clobbers
the previous one), and replace the while loop with one that never
terminates (because we did not set CSR_W_EI and CSR_W_IP is the
same bit, so obviously that bit will never turn on).

Note that on some hardware (SPARC V9 for instance), the CPU may
need special instructions inserted at various points. These
instructions may even depend on the memory model set in the CPU.
(In this case, if I remember right, at least one, maybe two, "membar
#StoreStore"s and/or a "membar #MemIssue" in RMO, nothing at all
in TSO, and just one "StoreStore" in PSO; this depends on the fact
that the CPU recognizes the same address for the reads and writes
of the CSR. If the status register had a different address, one
more membar would sometimes be required.)

See also the ongoing thread "Volatiles in assignment expressions".
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 10 '06 #8
On 2006-03-10, Richard G. Riley <rg*****@gmail.com> wrote:
"Jordan"posted the following on 2006-03-10:
On 2006-03-10, be***@uwalumni.com <be***@uwalumni.com> wrote:
Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits.
If you do that, a sprinkling of the "volatile" keyword may do something
for predictability
He claims it has been a 'C Standard' that it will be evaluted as a =
c; b = c.


His interpretaion of the standard is the same as mine.
I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?


Use volatile. You might still get the wrong answer, but it's more likely
to be consistent.


Could you explain how volatile changes anything here?


As far as I can tell, volatile restricts the compiler from making
optimizations that change the number or sense of accesses to the
variable in question.
It doesnt alter the limited bits in his memory mapped register and I
cant quite work out how it would make anything better : having said
that I only ever used volatile on HW port maps. Is that the issue
here? b is changing between "b=c" and "a=b"? Is this register a
read/write with some bits changing externally?
That's what the OP apparently says [i.e. some bits are changed to 0 at
the time of the write]
Then I see how volatile would work, but certainly wouldnt be using
a=b=c no matter what in this case.

Mar 10 '06 #9
Richard Heathfield <in*****@invalid.invalid> writes:
en******@yahoo.com said:
Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.


You are Dan Pop, and I claim my five pounds!


A questionable assumption in the absence of the phrase "engage your
brain".

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 11 '06 #10
en******@yahoo.com wrote:

Richard G. Riley wrote:
"en******@yahoo.com"posted the following on 2006-03-10:

Richard Heathfield wrote:
> be***@uwalumni.com said:
>
> > Hi All,
> >
> > A coworker and I have been debating the 'correct' expectation of
> > evaluation for the phrase a = b = c. Two different versions of GCC
> > ended up compiling this as b = c; a = b and the other ended up
> > compiling it as a = c; b = c. (Both with no optimizations enabled).
> > How did we notice you may ask? Well, in our case 'b' was a memory
> > mapped register that only has a select number of writable bits. He
> > claims it has been a 'C Standard' that it will be evaluted as a = c; b
> > = c. I personally believe that it would make more sense for it to be
> > evaluated as b = c; a = b, although I would never write code that has a
> > questionable operation. Can anyone settle this debate?
>
> The associativity is: a = (b = c); but the order of evaluation of a, b, and
> c is unspecified. The Standard only requires that the new values of a and b
> are provided at some time after the previous, and before the following,
> sequence point.
>
> So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
> a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
> combination that gives the same result.
>
> If you depend on the order of evaluation, any side effects of a, b, and c
> are likely to bite you eventually.

You missed the point of his question. Regardless of anything having
to do with evaluation order, the intermediate assignment to b can
affect the value that is assigned to a. int = unsigned char = int,
for example. If b is volatile that may also change the picture,
as another thread discusses. It isn't safe to assume (because
it's open to debate) that a = b = c may be replaced by b = c, a = b
even if b is volatile. But saying a = b = c means (in whatever
order) a = c and b = c is simply wrong.


Why? If you write the code properly and a,b,c are the same types and
none of them are physically volative and this is a single thread app
then I think the code can indeed infer equality. If not then we might
as well give up.

If they are not the same types then without the right casts you have
no right coding like this IMO because of hiccups down the line when
someone less familiar with the code comes along.


Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.


The point of interest is that
"assignment" is not a sequence point.

If
sorted -> next = *node;
sorted = *node;
is defined, then
sorted = sorted -> next = *node;
is undefined.
--
pete
Mar 11 '06 #11
Keith Thompson wrote:
Richard Heathfield <in*****@invalid.invalid> writes:
en******@yahoo.com said:
Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.


You are Dan Pop, and I claim my five pounds!


A questionable assumption in the absence of the phrase "engage your
brain".


Chapter and verse please.

Nyuk nyuk.
Mark F. Haigh
mf*****@sbcglobal.net

Mar 11 '06 #12

Richard Heathfield wrote:
en******@yahoo.com said:

Richard Heathfield wrote:

If you depend on the order of evaluation, any side effects of a, b, and c
are likely to bite you eventually.


You missed the point of his question. Regardless of anything having
to do with evaluation order, the intermediate assignment to b can
affect the value that is assigned to a.


I invite you to re-read my reply, especially the bit about side effects
(retained above).


I invite you to read the OP's posting again, and also the
description of how assignment expressions work in section
6.5.16. Your comment may have given useful advice but
wasn't really addressing the question asked. My comment was
on point, and also correct (of course you snipped the part
that explains that).

Chris Torek gave the best answer, being both on point and
a good explanation of the various issues.

Mar 11 '06 #13

pete wrote:
en******@yahoo.com wrote:

Richard G. Riley wrote:
"en******@yahoo.com"posted the following on 2006-03-10:

>
> Richard Heathfield wrote:
>> be***@uwalumni.com said:
>>
>> > Hi All,
>> >
>> > A coworker and I have been debating the 'correct' expectation of
>> > evaluation for the phrase a = b = c. Two different versions of GCC
>> > ended up compiling this as b = c; a = b and the other ended up
>> > compiling it as a = c; b = c. (Both with no optimizations enabled).
>> > How did we notice you may ask? Well, in our case 'b' was a memory
>> > mapped register that only has a select number of writable bits. He
>> > claims it has been a 'C Standard' that it will be evaluted as a = c; b
>> > = c. I personally believe that it would make more sense for it to be
>> > evaluated as b = c; a = b, although I would never write code that has a
>> > questionable operation. Can anyone settle this debate?
>>
>> The associativity is: a = (b = c); but the order of evaluation of a, b, and
>> c is unspecified. The Standard only requires that the new values of a and b
>> are provided at some time after the previous, and before the following,
>> sequence point.
>>
>> So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
>> a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
>> combination that gives the same result.
>>
>> If you depend on the order of evaluation, any side effects of a, b, and c
>> are likely to bite you eventually.
>
> You missed the point of his question. Regardless of anything having
> to do with evaluation order, the intermediate assignment to b can
> affect the value that is assigned to a. int = unsigned char = int,
> for example. If b is volatile that may also change the picture,
> as another thread discusses. It isn't safe to assume (because
> it's open to debate) that a = b = c may be replaced by b = c, a = b
> even if b is volatile. But saying a = b = c means (in whatever
> order) a = c and b = c is simply wrong.
>

Why? If you write the code properly and a,b,c are the same types and
none of them are physically volative and this is a single thread app
then I think the code can indeed infer equality. If not then we might
as well give up.

If they are not the same types then without the right casts you have
no right coding like this IMO because of hiccups down the line when
someone less familiar with the code comes along.


Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.


The point of interest is that
"assignment" is not a sequence point.

If
sorted -> next = *node;
sorted = *node;
is defined, then
sorted = sorted -> next = *node;
is undefined.


Even if that ridiculous claim were true, it isn't responsive
to the OP's question. Does the intermediate assignment
influence what value is assigned to a? The answer to that
is YES. Must the value that is written into b be read out
again to assign to a? The answer to that is NO (if b isn't
volatile) or MAYBE (if b is volatile). Sequence points are
an irrelevant side issue.

Mar 11 '06 #14

Richard G. Riley wrote:
"en******@yahoo.com"posted the following on 2006-03-10:

Richard G. Riley wrote:
"en******@yahoo.com"posted the following on 2006-03-10:

>
> Richard Heathfield wrote:
>> be***@uwalumni.com said:
>>
>> > Hi All,
>> >
>> > A coworker and I have been debating the 'correct' expectation of
>> > evaluation for the phrase a = b = c. Two different versions of GCC
>> > ended up compiling this as b = c; a = b and the other ended up
>> > compiling it as a = c; b = c. (Both with no optimizations enabled).
>> > How did we notice you may ask? Well, in our case 'b' was a memory
>> > mapped register that only has a select number of writable bits. He
>> > claims it has been a 'C Standard' that it will be evaluted as a = c; b
>> > = c. I personally believe that it would make more sense for it to be
>> > evaluated as b = c; a = b, although I would never write code that has a
>> > questionable operation. Can anyone settle this debate?
>>
>> The associativity is: a = (b = c); but the order of evaluation of a, b, and
>> c is unspecified. The Standard only requires that the new values of a and b
>> are provided at some time after the previous, and before the following,
>> sequence point.
>>
>> So gcc is quite within its rights to compile it to: a = c; b = c; or b = c;
>> a = c; or b = c; a = b; or tmp = c; a = tmp; b = tmp; or any other
>> combination that gives the same result.
>>
>> If you depend on the order of evaluation, any side effects of a, b, and c
>> are likely to bite you eventually.
>
> You missed the point of his question. Regardless of anything having
> to do with evaluation order, the intermediate assignment to b can
> affect the value that is assigned to a. int = unsigned char = int,
> for example. If b is volatile that may also change the picture,
> as another thread discusses. It isn't safe to assume (because
> it's open to debate) that a = b = c may be replaced by b = c, a = b
> even if b is volatile. But saying a = b = c means (in whatever
> order) a = c and b = c is simply wrong.
>

Why? If you write the code properly and a,b,c are the same types and
none of them are physically volative and this is a single thread app
then I think the code can indeed infer equality. If not then we might
as well give up.

If they are not the same types then without the right casts you have
no right coding like this IMO because of hiccups down the line when
someone less familiar with the code comes along.


Please try to pay attention. The question asked isn't about
whether a = b = c is good programming or whether anyone has
the "right" to use it in a program, but what the C Standard
says it means.


Do pay attention : it moved on to the affects of volatility : and it
is this I was asking about. It was also discussing real world issues
at this stage and the "standard" was another issue. Pay particular
attention to my comments about using C in the real world in the
paragraph beginngin with "Why?" - as you will see, it was a question
and not a statement : a question to the a=c and b=c is simply wrong
statement.


Don't be an idiot. The only one talking about "real world
issues" was you. Any questions about whether something is
"physically volatile" or we are dealing with a "single
threaded app" are completely irrelevant to the original
question and to my comments. Whether or not any of the
variables is volatile, the intermediate assignment to b
influences the value assigned to a; read section 6.5.16.
And don't presume that other people's assumptions match
your assumptions. More often than you expect, they don't.

Mar 11 '06 #15
en******@yahoo.com said:

Chris Torek gave the best answer


That is always true.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Mar 11 '06 #16
Richard Heathfield <in*****@invalid.invalid> writes:
en******@yahoo.com said:

Chris Torek gave the best answer


That is always true.


The best that the rest of us can hope for is to answer a question
earlier than Chris, or to answer a question that he doesn't.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Mar 11 '06 #17
en******@yahoo.com wrote:

pete wrote:
en******@yahoo.com wrote:

Richard G. Riley wrote:
> "en******@yahoo.com"posted the following on 2006-03-10:
>
> >
> > Richard Heathfield wrote:
> >> be***@uwalumni.com said:
> >>
> >> > Hi All,
> >> >
> >> > A coworker and I have been debating
> >> > the 'correct' expectation of
> >> > evaluation for the phrase a = b = c.
> >> > Two different versions of GCC
> >> > ended up compiling this as b = c; a = b
> >> > and the other ended up
> >> > compiling it as a = c; b = c.
> >> > (Both with no optimizations enabled).
> >> > How did we notice you may ask?
> >> > Well, in our case 'b' was a memory
> >> > mapped register that only has a select number
> >> > of writable bits. He
> >> > claims it has been a 'C Standard'
> >> > that it will be evaluted as a = c; b
> >> > = c. I personally believe that it
> >> > would make more sense for it to be
> >> > evaluated as b = c; a = b,
> >> > although I would never write code that has a
> >> > questionable operation. Can anyone settle this debate?
> >>
The point of interest is that
"assignment" is not a sequence point.

If
sorted -> next = *node;
sorted = *node;
is defined, then
sorted = sorted -> next = *node;
is undefined.
Even if that ridiculous claim were true,


The ridiculous claim is true.
The topic comes up on this newsgroup from time to time,
usually in the form of "p = p->next = q"
You can look it up next time you're online.

http://groups.google.com/group/comp....Enext+%3D+q%22

http://groups.google.com/group/comp....7e2102fd256d79

"The p = p->next = q problem is also a real problem that came from
a program I was writing when I posted a question about it here
years ago." -- Ben Pfaff
it isn't responsive
to the OP's question. Does the intermediate assignment
influence what value is assigned to a? The answer to that
is YES.


No.
The value of the intermediate assignment
influences what value is assigned to a,
but that value is known prior to the side effect
of the actual assignment taking place.

If you have
unsigned char uc;
unsigned int ui;
ui = uc = -1;
that can be translated as either
uc = UCHAR_MAX;
ui = UCHAR_MAX;
or
ui = UCHAR_MAX;
uc = UCHAR_MAX;
The order in which the side effects take place doesn't matter.

OP's question is entirely an issue of
side effects not being ordered between sequence points.

--
pete
Mar 11 '06 #18

pete wrote:
en******@yahoo.com wrote:

pete wrote:
en******@yahoo.com wrote:
>
> Richard G. Riley wrote:
> > "en******@yahoo.com"posted the following on 2006-03-10:
> >
> > >
> > > Richard Heathfield wrote:
> > >> be***@uwalumni.com said:
> > >>
> > >> > Hi All,
> > >> >
> > >> > A coworker and I have been debating
> > >> > the 'correct' expectation of
> > >> > evaluation for the phrase a = b = c.
> > >> > Two different versions of GCC
> > >> > ended up compiling this as b = c; a = b
> > >> > and the other ended up
> > >> > compiling it as a = c; b = c.
> > >> > (Both with no optimizations enabled).
> > >> > How did we notice you may ask?
> > >> > Well, in our case 'b' was a memory
> > >> > mapped register that only has a select number
> > >> > of writable bits. He
> > >> > claims it has been a 'C Standard'
> > >> > that it will be evaluted as a = c; b
> > >> > = c. I personally believe that it
> > >> > would make more sense for it to be
> > >> > evaluated as b = c; a = b,
> > >> > although I would never write code that has a
> > >> > questionable operation. Can anyone settle this debate?
> > >> The point of interest is that
"assignment" is not a sequence point.

If
sorted -> next = *node;
sorted = *node;
is defined, then
sorted = sorted -> next = *node;
is undefined.
Even if that ridiculous claim were true,


The ridiculous claim is true.
The topic comes up on this newsgroup from time to time,
usually in the form of "p = p->next = q"
You can look it up next time you're online.

http://groups.google.com/group/comp....Enext+%3D+q%22

http://groups.google.com/group/comp....7e2102fd256d79

"The p = p->next = q problem is also a real problem that came from
a program I was writing when I posted a question about it here
years ago." -- Ben Pfaff


Excuse me while I stop laughing. Any compiler that compiles
p = p->next = q as storing into p before fetching p->next is
simply broken. Operands are evaluated before the operator
they're operands for, and operators are evaluated before
they produce a value--that's just how C semantics work (in
a C abstract machine of course). The same thing is true for
assignment: only the *side effect* of updating the object
being assigned might be delayed until the next sequence
point. And there's no point in allowing an "optimization"
which if it's allowed causes people to stop using the very
construct being optimized.

If it were permitted to evaluate operators before operands
when the resulting value is "known" then this code could get
undefined behavior -

unsigned u = 12345, *p = &u;
p += 1|(0&*p);

The idea that p = p->next = q is allowed to store into
p before evaluating p->next doesn't pass the laugh test.
it isn't responsive
to the OP's question. Does the intermediate assignment
influence what value is assigned to a? The answer to that
is YES.


No.
The value of the intermediate assignment
influences what value is assigned to a,
but that value is known prior to the side effect
of the actual assignment taking place.


The "intermediate assignment" I'm talking about is the text
"b =", not any run time operation.
If you have
unsigned char uc;
unsigned int ui;
ui = uc = -1;
that can be translated as either
uc = UCHAR_MAX;
ui = UCHAR_MAX;
or
ui = UCHAR_MAX;
uc = UCHAR_MAX;
The order in which the side effects take place doesn't matter.

OP's question is entirely an issue of
side effects not being ordered between sequence points.


If you think that then you didn't understand the question
the OP was trying to ask.

Mar 12 '06 #19
en******@yahoo.com writes:
Any compiler that compiles p = p->next = q as storing into p
before fetching p->next is simply broken. Operands are
evaluated before the operator they're operands for, and
operators are evaluated before they produce a value--that's
just how C semantics work (in a C abstract machine of course).


Do you have any citations to back up your assertions?
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Mar 12 '06 #20
Ben Pfaff wrote:

en******@yahoo.com writes:
Any compiler that compiles p = p->next = q as storing into p
before fetching p->next is simply broken. Operands are
evaluated before the operator they're operands for, and
operators are evaluated before they produce a value--that's
just how C semantics work (in a C abstract machine of course).


Do you have any citations to back up your assertions?


I think he's confused about sequence points.
Some of the standard's function operator descriptions
seem to order the sequence of events between sequence points,
without proper respect to the concept of sequence points.

Here, we see the standard claim that the postfix increment
takes place after the result is obtained:
N869
6.5.2.4 Postfix increment and decrement operators
[#2] The result of the postfix ++ operator is the value of
the operand. After the result is obtained, the value of the
operand is incremented.

But, if we look at
N869
5.1.2.3 Program execution
[#16] EXAMPLE 7
"sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));
but the actual increment of p can occur at any time between
the previous sequence point and the next sequence point "

.... we see the standard deny any ordering of events
between sequence points.

In the p = p->next = q thread discussion, a lot of people quoted:
N869
6.5 Expressions
[#2] Furthermore, the prior value
shall be accessed only to determine the value to be
stored.60)
60)This paragraph renders undefined statement expressions
such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

.... but I don't think that's really what makes the case for
undefinedness,
because that would imply that there is something wrong with
p = p->next
and I don't think that there is anything wrong with
p = p->next

I think it's just simply that assignments aren't sequence points,
which is what the problem is with
p = p->next = q.

--
pete
Mar 12 '06 #21
pete wrote:
In the p = p->next = q thread discussion, a lot of people quoted:
N869
6.5 Expressions
[#2] Furthermore, the prior value
shall be accessed only to determine the value to be
stored.60)
60)This paragraph renders undefined statement expressions
such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

... but I don't think that's really what makes the case for
undefinedness,
because that would imply that there is something wrong with
p = p->next
and I don't think that there is anything wrong with
p = p->next

I think it's just simply that assignments aren't sequence points,
which is what the problem is with
p = p->next = q.


I've been mulling this, and I've come to think that my
p = p->next
implication, is incorrect.
In the multiple assignment expression, "the prior value", (p),
is also accessed to determine which object
is the lvalue in the assignment from q
p->next = q

I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.

--
pete
Mar 12 '06 #22
On 2006-03-12, pete <pf*****@mindspring.com> wrote:

I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.

but

p=(p->next=q);

is fine? I hope .
Mar 12 '06 #23
Richard G. Riley schrieb:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:
I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.


but

p=(p->next=q);

is fine? I hope .


No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points; parentheses
do not introduce new sequence points.
If you want to be on the safe side, you can only do
p->next = q, p = p->next;
which IMO does not give you any advantage over
p->next = q;
p = p->next;

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Mar 12 '06 #24
"Richard G. Riley" <rg****@gmail.com> writes:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:

I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.


but
p=(p->next=q);
is fine? I hope .


Why would you think it to be any different? Parentheses do not
insert a sequence point.
--
Just another C hacker.
Mar 12 '06 #25
On 2006-03-12, Michael Mair <Mi**********@invalid.invalid> wrote:
Richard G. Riley schrieb:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:
I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.


but

p=(p->next=q);

is fine? I hope .


No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points; parentheses
do not introduce new sequence points.
If you want to be on the safe side, you can only do
p->next = q, p = p->next;
which IMO does not give you any advantage over
p->next = q;
p = p->next;

Cheers
Michael


Well, thats a shit load of legacy code I didnt properly break down
then. Mind you, I'm sure there was never a problem.

I'm truly astonished at this.

But looking at it anyway its not quite as "common" as

a=b=c=1;

Whats the problem with the above? Anything? (Assuming single thread
etc).

Mar 12 '06 #26
"Richard G. Riley" <rg****@gmail.com> writes:
a=b=c=1;

Whats the problem with the above?


Nothing. It's fine.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Mar 12 '06 #27

"pete" <pf*****@mindspring.com> wrote in message
news:44***********@mindspring.com...
Ben Pfaff wrote:

en******@yahoo.com writes:
Any compiler that compiles p = p->next = q as storing into p
before fetching p->next is simply broken. Operands are
evaluated before the operator they're operands for, and
operators are evaluated before they produce a value--that's
just how C semantics work (in a C abstract machine of course).


Do you have any citations to back up your assertions?


I think he's confused about sequence points.
Some of the standard's function operator descriptions
seem to order the sequence of events between sequence points,
without proper respect to the concept of sequence points.

Here, we see the standard claim that the postfix increment
takes place after the result is obtained:
N869
6.5.2.4 Postfix increment and decrement operators
[#2] The result of the postfix ++ operator is the value of
the operand. After the result is obtained, the value of the
operand is incremented.

But, if we look at
N869
5.1.2.3 Program execution
[#16] EXAMPLE 7
"sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));
but the actual increment of p can occur at any time between
the previous sequence point and the next sequence point "

... we see the standard deny any ordering of events
between sequence points.

But the standard isn't just a collection of sayings to be quoted out of
context. You have to follow the narrative.

The first quote here is defining the semantics of the abstract machine.

The second quote occurs as part of a long discussion of the "as-if" rule,
i.e. the extent to which an implementation may or may not depart from the
abstract machine.

The second quote doesn't contradict the first. On the contrary, it
presupposes the first: if the semantics of the abstract machine were
unspecified, there wouldn't be much point in saying that the real machine
has more latitude.

--
RSH
Mar 13 '06 #28
Michael Mair <Mi**********@invalid.invalid> writes:
Richard G. Riley schrieb:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:
I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.

but
p=(p->next=q);
is fine? I hope .


No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points


Well, no he's not. But he's reading its prior value for purposes other
than to determine the value stored, so same deal.
Mar 14 '06 #29
Micah Cowan schrieb:
Michael Mair <Mi**********@invalid.invalid> writes:

Richard G. Riley schrieb:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:
I'm coming around to thinking that 6.5 [#2] is relevant, and that
p = p->next = q
is undefined, and not just unspecified.

but
p=(p->next=q);
is fine? I hope .


No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points


Well, no he's not. But he's reading its prior value for purposes other
than to determine the value stored, so same deal.


You are right, thanks for the correction.

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Mar 14 '06 #30

Ben Pfaff wrote:
en******@yahoo.com writes:
Any compiler that compiles p = p->next = q as storing into p
before fetching p->next is simply broken. Operands are
evaluated before the operator they're operands for, and
operators are evaluated before they produce a value--that's
just how C semantics work (in a C abstract machine of course).


Do you have any citations to back up your assertions?


"Evaluation of an expression may _produce_ side effects."

"[At sequence points,] all side effects of _previous_
evaluations shall be complete [...]."

"In the abstract machine, all expressions are evaluated
_as specified by the semantics_."

"[An operator] may specify an operation to be performed
(which _in turn_ may _yield a value_ [...], _produce_ a
side effect, or some combination thereof) [...]."

"The syntax specifies the precedence of operators _in the
evaluation of_ an expression [...]."

"[Except ...], _the order of evaluation of subexpressions_
and _the order in which side effects take place_ are both
unspecified." (Not "order of A and B" but "order of A" and
"order of B".)

Keeping these in mind, read through section 6.5, noting
which paragraphs are marked "Semantics". Expressions
are evaluated "as specified by the semantics".

Mar 14 '06 #31

pete wrote:
Ben Pfaff wrote:

en******@yahoo.com writes:
Any compiler that compiles p = p->next = q as storing into p
before fetching p->next is simply broken. Operands are
evaluated before the operator they're operands for, and
operators are evaluated before they produce a value--that's
just how C semantics work (in a C abstract machine of course).
Do you have any citations to back up your assertions?


I think he's confused about sequence points.


I assure you I understand sequence points quite well.
Some of the standard's function operator descriptions
seem to order the sequence of events between sequence points,
without proper respect to the concept of sequence points.

Here, we see the standard claim that the postfix increment
takes place after the result is obtained:
N869
6.5.2.4 Postfix increment and decrement operators
[#2] The result of the postfix ++ operator is the value of
the operand. After the result is obtained, the value of the
operand is incremented.

But, if we look at
N869
5.1.2.3 Program execution
[#16] EXAMPLE 7
"sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));
but the actual increment of p can occur at any time between
the previous sequence point and the next sequence point "

... we see the standard deny any ordering of events
between sequence points.


You're not reading carefully enough. The order in which
_side effects_ take place is unspecified, but _some_
evaluation must precede _any_ side effect, because it is
evaluations that produce side effects. The "at any time"
in the comment above means relative to other side effects.

Mar 14 '06 #32

Micah Cowan wrote:
Michael Mair <Mi**********@invalid.invalid> writes:
Richard G. Riley schrieb:
On 2006-03-12, pete <pf*****@mindspring.com> wrote:

> I'm coming around to thinking that 6.5 [#2] is relevant, and that
> p = p->next = q
>is undefined, and not just unspecified.
but
p=(p->next=q);
is fine? I hope .


No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points


Well, no he's not. But he's reading its prior value for purposes other
than to determine the value stored, so same deal.


Look again. Reading p is necessary to evaluate p->q = next,
and evaluating p->q = next is necessary to get the value
that's assigned to p.

Mar 14 '06 #33
en******@yahoo.com wrote:
The order in which
_side effects_ take place is unspecified, but _some_
evaluation must precede _any_ side effect, because it is
evaluations that produce side effects.
It's possible for all evaluations to be completed
before any side effects take place.
The "at any time"
in the comment above means relative to other side effects.


Hence we get OP's situation:
"A coworker and I have been debating the 'correct' expectation
of evaluation for the phrase a = b = c.
Two different versions of GCC ended up compiling this as
b = c; a = b
and the other ended up compiling it as
a = c; b = c. "

--
pete
Mar 14 '06 #34
en******@yahoo.com wrote:

Micah Cowan wrote:
Michael Mair <Mi**********@invalid.invalid> writes:
Richard G. Riley schrieb:
> On 2006-03-12, pete <pf*****@mindspring.com> wrote:
>
>> I'm coming around to thinking that 6.5 [#2] is relevant, and that
>> p = p->next = q
>>is undefined, and not just unspecified.
> but
> p=(p->next=q);
> is fine? I hope .

No. Whether you write
a = b = c;
or
a = (b = c);
does not change anything -- apart from clarifying your intent.
You still are modifying p twice between sequence points
Well, no he's not.
But he's reading its prior value for purposes other
than to determine the value stored, so same deal.


Look again. Reading p is necessary to evaluate p->q = next,


No, it isn't.
The value of (p->q = next) is (next)
and evaluating p->q = next is necessary to get the value
that's assigned to p.


--
pete
Mar 14 '06 #35
en******@yahoo.com writes:
Ben Pfaff wrote:
en******@yahoo.com writes:
> Any compiler that compiles p = p->next = q as storing into p
> before fetching p->next is simply broken. Operands are
> evaluated before the operator they're operands for, and
> operators are evaluated before they produce a value--that's
> just how C semantics work (in a C abstract machine of course).
Do you have any citations to back up your assertions?


"Evaluation of an expression may _produce_ side effects."

"[At sequence points,] all side effects of _previous_
evaluations shall be complete [...]."

"In the abstract machine, all expressions are evaluated
_as specified by the semantics_."


OK.
"[An operator] may specify an operation to be performed
(which _in turn_ may _yield a value_ [...], _produce_ a
side effect, or some combination thereof) [...]."
I don't see anything about ordering there.
"The syntax specifies the precedence of operators _in the
evaluation of_ an expression [...]."
Precedence != ordering.
"[Except ...], _the order of evaluation of subexpressions_
and _the order in which side effects take place_ are both
unspecified." (Not "order of A and B" but "order of A" and
"order of B".)
I don't think that typographical distinction is a good one to
hinge an argument on. "the order of" could be repeated just for
clarity of exposition. Even if the typography is significant
here, I don't think it gets you where you want to go.
Keeping these in mind, read through section 6.5, noting
which paragraphs are marked "Semantics". Expressions
are evaluated "as specified by the semantics".


OK. Let's look at section 6.15.6 "Assignment operators":

3 ... The side effect of updating the stored value of the
left operand shall occur between the previous and the
next sequence point.

4 The order of evaluation of the operands is
unspecified. ...

It seems pretty clear that both the order of evaluation of the
operands and the time at which the result is stored are both
rather unconstrained.
--
"The lusers I know are so clueless, that if they were dipped in clue
musk and dropped in the middle of pack of horny clues, on clue prom
night during clue happy hour, they still couldn't get a clue."
--Michael Girdwood, in the monastery
Mar 14 '06 #36

"Ben Pfaff" <bl*@cs.stanford.edu> wrote in message
news:87************@benpfaff.org...
en******@yahoo.com writes:
Ben Pfaff wrote:
en******@yahoo.com writes:

> Any compiler that compiles p = p->next = q as storing into p
> before fetching p->next is simply broken. Operands are
> evaluated before the operator they're operands for, and
> operators are evaluated before they produce a value--that's
> just how C semantics work (in a C abstract machine of course).

Do you have any citations to back up your assertions?
"Evaluation of an expression may _produce_ side effects."

"[At sequence points,] all side effects of _previous_
evaluations shall be complete [...]."

"In the abstract machine, all expressions are evaluated
_as specified by the semantics_."


OK.
"[An operator] may specify an operation to be performed
(which _in turn_ may _yield a value_ [...], _produce_ a
side effect, or some combination thereof) [...]."


I don't see anything about ordering there.
"The syntax specifies the precedence of operators _in the
evaluation of_ an expression [...]."


Precedence != ordering.

Precedence puts unavoidable contraints on ordering, because it establishes
which subexpressions are the operands of other expressions.

"[Except ...], _the order of evaluation of subexpressions_
and _the order in which side effects take place_ are both
unspecified." (Not "order of A and B" but "order of A" and
"order of B".)


I don't think that typographical distinction is a good one to
hinge an argument on. "the order of" could be repeated just for
clarity of exposition. Even if the typography is significant
here, I don't think it gets you where you want to go.
Keeping these in mind, read through section 6.5, noting
which paragraphs are marked "Semantics". Expressions
are evaluated "as specified by the semantics".


OK. Let's look at section 6.15.6 "Assignment operators":

3 ... The side effect of updating the stored value of the
left operand shall occur between the previous and the
next sequence point.

4 The order of evaluation of the operands is
unspecified. ...

In p = p->next = q there are two assignments, so 6.15.6 has to be applied to
each of them separately.

4 The order of evaluation of the operands is
unspecified. ...

Well each assignment has left and right operands, and in each case it makes
no difference whether we evaluate the left before the right or vice versa.
Nobody is claiming otherwise. It's a non-issue.

But nothing here contradicts the fact that one assignment must be evaluated
before the other, for the simple reason that the value of one is an operand
of the other. "Evaluated" here means fully evaluated according to the
semantics -- the abstract machine has no optimiser and no licence to
simplify, so just doing enough to ascertain the value doesn't qualify.
3 ... The side effect of updating the stored value of the
left operand shall occur between the previous and the
next sequence point.

The wording is very specific. "The side effect of updating the stored
value" (of an object referenced by an lvalue) doesn't extend to computing
the lvalue in question. The evaluation of the left operand of an assignment
is not part of the side effect.

The timing of the side effect is only an issue for the outer assignment.
And the quote above only puts outer limits on when the side effect occurs.
It doesn't say that the side effect may occur at any time between the
sequence points -- of course that would be silly, because the new value has
to be computed before it can be stored, so the side effect cannot occur
before the evaluation of the expression which provides the new value.
Another constraint on ordering that is too obvious to be stated, but is not
overridden by any wording.

It seems pretty clear that both the order of evaluation of the
operands and the time at which the result is stored are both
rather unconstrained.

That's an interesting approach: two insignificant details are left
unspecified, so it must be saying "anything goes"

Mar 14 '06 #37
You (Robin Haigh) believe that
p = p->next = q;
is well defined. Many other people share this opinion. But when
it was brought up in comp.std.c a long time ago, there were also
many people with the opposite opinion. If I recall correctly,
some of these folks were actually committee members. I'm not
going to waste a lot more of my time resuming the debate. It's
not productive. Go back and read the old thread.

--
"Am I missing something?"
--Dan Pop
Mar 14 '06 #38

"Ben Pfaff" <bl*@cs.stanford.edu> wrote in message
news:87************@benpfaff.org...
You (Robin Haigh) believe that
p = p->next = q;
is well defined. Many other people share this opinion. But when
it was brought up in comp.std.c a long time ago, there were also
many people with the opposite opinion. If I recall correctly,
some of these folks were actually committee members. I'm not
going to waste a lot more of my time resuming the debate. It's
not productive. Go back and read the old thread.

Well I wouldn't claim that the standard is crystal clear on the subject.

However, if this expression produces undefined behaviour, it can only be
because of 6.5/2. Trouble is, an enthusiastic reading of 6.5/2 can make all
sorts of things UB, including *p++. A line has to be drawn, and it might
seem important to know where it is.

One way to draw a line is to say that the old value (of the modified object)
can be used within the subexpression that computes the new value. This is
rational, workable, creates no difficulties or ambiguities, conflicts with
nothing in the standard, and finds support in the Rationale.

Many people have claimed that the line is somewhere else, but nobody seems
to be offering a workable detailed exposition of where they think it is.
The other approach (with p = p->next = q) is to argue that maybe 6.5/2
doesn't apply, but the outcome is still unspecified as a result of the
"reordering" licence given to the abstract machine.

Well it seems to me that 6.5/2 is intended to cover, and does cover, _at
least_ all the cases where the reordering licence creates an ambiguity, as
regards the value of an expression or as regards the final stored value of
any object (at the next sequence point). This doesn't leave any room for
outcomes to be unspecified as to these aspects. So the effect of the
reordering licence on any expression that isn't UB is invisible, unless
there are external consequences of side effects, such as file output or
asynchronous access to objects.

--
RSH

Mar 15 '06 #39
Robin Haigh wrote:
Trouble is, an enthusiastic reading of 6.5/2 can make all
sorts of things UB, including *p++.


An enthusiastic reading of 6.5/2 should find the footnote:

70)
This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

--
pete
Mar 15 '06 #40

"pete" <pf*****@mindspring.com> wrote in message
news:44***********@mindspring.com...
Robin Haigh wrote:
Trouble is, an enthusiastic reading of 6.5/2 can make all
sorts of things UB, including *p++.


An enthusiastic reading of 6.5/2 should find the footnote:

70)
This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

Can you see how this footnote helps? I can't

--
RSH
Mar 15 '06 #41

Ben Pfaff wrote:
en******@yahoo.com writes:
Ben Pfaff wrote:
en******@yahoo.com writes:

> Any compiler that compiles p = p->next = q as storing into p
> before fetching p->next is simply broken. Operands are
> evaluated before the operator they're operands for, and
> operators are evaluated before they produce a value--that's
> just how C semantics work (in a C abstract machine of course).

Do you have any citations to back up your assertions?


"Evaluation of an expression may _produce_ side effects."

"[At sequence points,] all side effects of _previous_
evaluations shall be complete [...]."

"In the abstract machine, all expressions are evaluated
_as specified by the semantics_."


OK.
"[An operator] may specify an operation to be performed
(which _in turn_ may _yield a value_ [...], _produce_ a
side effect, or some combination thereof) [...]."


I don't see anything about ordering there.


Maybe in some imaginary world where words have no intrinsic
meaning. In _this_ world where the writing is a mixture of
informal and semi-formal English, the words used clearly say
something about ordering because of causality relationships.
"The syntax specifies the precedence of operators _in the
evaluation of_ an expression [...]."


Precedence != ordering.


Again, the word precedence implies something about
ordering because of the meaning of the word. The
root of precedence is precede.
"[Except ...], _the order of evaluation of subexpressions_
and _the order in which side effects take place_ are both
unspecified." (Not "order of A and B" but "order of A" and
"order of B".)


I don't think that typographical distinction is a good one to
hinge an argument on. "the order of" could be repeated just for
clarity of exposition. Even if the typography is significant
here, I don't think it gets you where you want to go.


Some people think that the standard says the ordering of any
events whatsoever between sequence points is completely
unconstrained. But that's not what it says. If you read
the defining paragraph for sequence points, you'll see that
sequence points are mentioned in relation to the relative
order of _side effects_. In the Semantics paragraphs there
never is a statement that side effects are unordered
relative to expression evaluations. On the contrary, it's
always side effects of _previous_ evaluations.

The standard takes pains to point out _in every case_ in the
various Semantics paragraphs each case where sequence points
come into play in determining (or not determing) ordering,
and it's always about side effects, nothing else. Since
trouble is taken to point out _exceptions_ to ordering
relationships, the clear implication is that other parts of
the standard use words with their normal sense of causality
and ordering relationships.

The sentence quoted above is just confirmation that the
standard intends to talk about (non-)ordering of side effects
relative to each other, and not relative to other events.
Keeping these in mind, read through section 6.5, noting
which paragraphs are marked "Semantics". Expressions
are evaluated "as specified by the semantics".


OK. Let's look at section 6.15.6 "Assignment operators":

3 ... The side effect of updating the stored value of the
left operand shall occur between the previous and the
next sequence point.

4 The order of evaluation of the operands is
unspecified. ...

It seems pretty clear that both the order of evaluation of the
operands and the time at which the result is stored are both
rather unconstrained.


Only when read in isolation. When read in conjunction with
the other statements quoted above, since the evaluation
_produces_ the side effect, obviously the evaluation has to
come first.

Mar 17 '06 #42

pete wrote:
en******@yahoo.com wrote:
The order in which
_side effects_ take place is unspecified, but _some_
evaluation must precede _any_ side effect, because it is
evaluations that produce side effects.


It's possible for all evaluations to be completed
before any side effects take place.


Sure it is. What is _not_ possible is for any side
effect to precede the expression evaluation that
produces it. Did you miss the point of what I
was saying?
The "at any time"
in the comment above means relative to other side effects.


Hence we get OP's situation:
"A coworker and I have been debating the 'correct' expectation
of evaluation for the phrase a = b = c.
Two different versions of GCC ended up compiling this as
b = c; a = b
and the other ended up compiling it as
a = c; b = c. "


Yes, the situation _arose_ because the storing of a can
precede the storing of b. But the question the OP was
asking was about the semantics of the assignment operator.
When the side effects happen is part of those semantics,
but not the main point OP was asking about.

Mar 17 '06 #43

pete wrote:
en******@yahoo.com wrote:

Micah Cowan wrote:
Michael Mair <Mi**********@invalid.invalid> writes:

> Richard G. Riley schrieb:
> > On 2006-03-12, pete <pf*****@mindspring.com> wrote:
> >
> >> I'm coming around to thinking that 6.5 [#2] is relevant, and that
> >> p = p->next = q
> >>is undefined, and not just unspecified.
> > but
> > p=(p->next=q);
> > is fine? I hope .
>
> No. Whether you write
> a = b = c;
> or
> a = (b = c);
> does not change anything -- apart from clarifying your intent.
> You still are modifying p twice between sequence points

Well, no he's not.
But he's reading its prior value for purposes other
than to determine the value stored, so same deal.


Look again. Reading p is necessary to evaluate p->q = next,


No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.

Mar 17 '06 #44
On Friday 17 March 2006 04:48, en******@yahoo.com opined (in
<11*********************@i39g2000cwa.googlegroups. com>):

pete wrote:
en******@yahoo.com wrote:
>
> Micah Cowan wrote:
> > Michael Mair <Mi**********@invalid.invalid> writes:
> >
> > > Richard G. Riley schrieb:
> > > > On 2006-03-12, pete <pf*****@mindspring.com> wrote:
> > > >
> > > >> I'm coming around to thinking that 6.5 [#2] is relevant, and
> > > >> that p = p->next = q
> > > >>is undefined, and not just unspecified.
> > > > but
> > > > p=(p->next=q);
> > > > is fine? I hope .
> > >
> > > No. Whether you write
> > > a = b = c;
> > > or
> > > a = (b = c);
> > > does not change anything -- apart from clarifying your intent.
> > > You still are modifying p twice between sequence points
> >
> > Well, no he's not.
> > But he's reading its prior value for purposes other
> > than to determine the value stored, so same deal.
>
> Look again. Reading p is necessary to evaluate p->q = next,


No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.

--
BR, Vladimir

How long a minute is depends on which side of the bathroom door you're
on.

Mar 17 '06 #45

Vladimir S. Oka wrote:
On Friday 17 March 2006 04:48, en******@yahoo.com opined (in
<11*********************@i39g2000cwa.googlegroups. com>):

pete wrote:
en******@yahoo.com wrote:
>
> Micah Cowan wrote:
> > Michael Mair <Mi**********@invalid.invalid> writes:
> >
> > > Richard G. Riley schrieb:
> > > > On 2006-03-12, pete <pf*****@mindspring.com> wrote:
> > > >
> > > >> I'm coming around to thinking that 6.5 [#2] is relevant, and
> > > >> that p = p->next = q
> > > >>is undefined, and not just unspecified.
> > > > but
> > > > p=(p->next=q);
> > > > is fine? I hope .
> > >
> > > No. Whether you write
> > > a = b = c;
> > > or
> > > a = (b = c);
> > > does not change anything -- apart from clarifying your intent.
> > > You still are modifying p twice between sequence points
> >
> > Well, no he's not.
> > But he's reading its prior value for purposes other
> > than to determine the value stored, so same deal.
>
> Look again. Reading p is necessary to evaluate p->q = next,

No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.


You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.

Mar 17 '06 #46
On Friday 17 March 2006 15:27, en******@yahoo.com opined (in
<11**********************@j52g2000cwj.googlegroups .com>):

Vladimir S. Oka wrote:
On Friday 17 March 2006 04:48, en******@yahoo.com opined (in
<11*********************@i39g2000cwa.googlegroups. com>):
>
> pete wrote:
>> en******@yahoo.com wrote:
>> >
>> > Micah Cowan wrote:
>> > > Michael Mair <Mi**********@invalid.invalid> writes:
>> > >
>> > > > Richard G. Riley schrieb:
>> > > > > On 2006-03-12, pete <pf*****@mindspring.com> wrote:
>> > > > >
>> > > > >> I'm coming around to thinking that 6.5 [#2] is relevant,
>> > > > >> and that p = p->next = q
>> > > > >>is undefined, and not just unspecified.
>> > > > > but
>> > > > > p=(p->next=q);
>> > > > > is fine? I hope .
>> > > >
>> > > > No. Whether you write
>> > > > a = b = c;
>> > > > or
>> > > > a = (b = c);
>> > > > does not change anything -- apart from clarifying your
>> > > > intent. You still are modifying p twice between sequence
>> > > > points
>> > >
>> > > Well, no he's not.
>> > > But he's reading its prior value for purposes other
>> > > than to determine the value stored, so same deal.
>> >
>> > Look again. Reading p is necessary to evaluate p->q = next,
>>
>> No, it isn't.
>> The value of (p->q = next) is (next)
>
> The value of p->q = next is next. But in order to get the
> value, the assignment p->q = next must _have been
> evaluated_, which needed both operands. Evaluation includes
> all the actions in the Semantics paragraph, which includes
> starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q
= next) _will_be_ next before it even produces any code, and can use
that knowledge once it does get to producing some.


You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.


But it still does not evaluate p->q in order to assign next to it. What
is evaluated is next, and its value is /assigned/ to p->q. Next, the
assignment is evaluated and assigned to p. The assignment evaluates to
next, but I don't think that compiler is obliged to do that in any
particular way.

--
BR, Vladimir

Writing about music is like dancing about architecture.
-- Frank Zappa

Mar 17 '06 #47
[on whether
p = p->next = next;
could have undefined behavior]
Vladimir S. Oka wrote:
I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.

In article <11**********************@j52g2000cwj.googlegroups .com>
<en******@yahoo.com> wrote:You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.


This is correct -- in order to claim to compile Standard C, a C
compiler must obey the standard -- but the question is whether
"everything else in the standard" actually *says* that

p = p->next = next;

has to have defined behavior. You and I may think it is bizarre
and wrong if the actual wording in the Standard fails to require
this to work the "obvious" and "correct" way. Unfortunately, those
who argue that both C89 and C99 fail to require this to work, do
in fact seem to have a leg to stand on, as the saying goes.

(The standard has a number of defects, and I consider this to be
one of them, albeit a minor one. Someone's -- I have forgotten
whose -- proposed annex to the C99 standard, with a formal
model for deciding sequence points, would have at least provided
a definitive answer. But that annex did not make it in.)

(There is a simple cure available to the C programmer, though: just
write:

p->next = next, p = next;

instead. We can avoid skating on the thin ice, instead of arguing
about just how thin it may be.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 17 '06 #48
en******@yahoo.com writes:
pete wrote:
No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_,


Wrong. The assignment itself need not have taken place. If you really
/did/ understand sequence points, you would know this.

As far as C is concerned, an implementation is more than welcome to do

p = next;
p->q = next;

That's why sequence points are very important.
Mar 17 '06 #49

In article <87************@benpfaff.org>, Ben Pfaff <bl*@cs.stanford.edu> writes:
You (Robin Haigh) believe that
p = p->next = q;
is well defined. Many other people share this opinion. But when
it was brought up in comp.std.c a long time ago, there were also
many people with the opposite opinion. If I recall correctly,
some of these folks were actually committee members.


It's my feeling that any question of the C standard which leads to
an extended argument between Lawrence Kirby and Douglas Gwyn[1] is
pretty much by definition an unclear matter.

I agree with Ben. It's not productive. Avoid multiple assignments
between sequence points where ordering could be significant, and not
only is the potential problem avoided, but the resulting code will
be simpler and clearer.
1. http://groups.google.com/group/comp....ab46d713d239a2

--
Michael Wojcik mi************@microfocus.com

Do not "test" parts, as this may compromise sensitive joinery. Those who
suffer difficulty should abandon the enterprise immediately. -- Chris Ware
Mar 18 '06 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.