473,395 Members | 1,969 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Ambiguity in semantics of assignments?

Here's some code that's giving me differing results, depending
on the compiler.

[includes omitted]

typedef foo {
int A,B;
} FOO;

int main() {
int A;
FOO foo;

A = 57;
foo.A = 42;

A = foo.A += A; /* crucial statement */

printf("A = %d; foo.A = %d\n",A,foo.A);

return 0;
}

Using Cygwin gcc 3.3.3, I get 99 for both A and foo.A.
Using a different compiler, I get 84 for both A and foo.A.

The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?

-- Paul
Nov 14 '05 #1
21 1859
In article <9b*************************@posting.google.com> ,
Paul Steckler <st***@ccs.neu.edu> wrote:
Here's some code that's giving me differing results, depending
on the compiler.

[includes omitted]

typedef foo {
int A,B;
} FOO;

int main() {
int A;
FOO foo;

A = 57;
foo.A = 42;

A = foo.A += A; /* crucial statement */

printf("A = %d; foo.A = %d\n",A,foo.A);

return 0;
}

Using Cygwin gcc 3.3.3, I get 99 for both A and foo.A.
Using a different compiler, I get 84 for both A and foo.A.
(Which compiler?)

The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?


I don't see any.

The first suspect is invoking undefined behavior by both changing
an object's value and using an its value for something other than
calculating the new value to be stored between sequence points (N869
6.5#2), but you're not doing that here.

Is the code you posted, plus #including <stdio.h> for the printf,
a complete program that demonstrates the problem?
If not, there's probably something in the part you cut out that's
introducing an ambiguity; find it and fix it. If it is, especially if
you get different behavior by using two int variables directly instead
of wrapping them in a struct, you may have encountered a compiler bug.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
Analogy: you are asking a bunch of violinists about the finer points of
playing the tuba. ... [L]eave us poor violinists alone; we're strung
out enough already. --Eric Sosman in comp.lang.c
Nov 14 '05 #2
Paul Steckler wrote:
Here's some code that's giving me differing results, depending
on the compiler.

[includes omitted]

typedef foo {
int A,B;
} FOO;

int main() {
int A;
FOO foo;

A = 57;
foo.A = 42;

A = foo.A += A; /* crucial statement */

printf("A = %d; foo.A = %d\n",A,foo.A);

return 0;
}

Using Cygwin gcc 3.3.3, I get 99 for both A and foo.A.
Using a different compiler, I get 84 for both A and foo.A.

The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?


The statement is worse than ambiguous; it's meaningless
because it resides in a non-C source. Once the compiler
issues the required diagnostic it's free to go ahead and
translate the non-C program, but the Standard no longer
governs what happens when and if the program is executed.

Things would have been different if there had been a
`struct' or `union' keyword right after the `typedef', or
if `foo' had been #define'd as `struct' or `union' itself.
Had that been the case, there would have been no ambiguity,
the Standard would have remained in force, and both outputs
would have been 99.

But as the code stands, both compilers are "right" --
provided they've issued that diagnostic, of course.

(You *did* cut and paste the actual code, didn't you?
Surely you wouldn't have been foolhardy enough to post an
inaccurate paraphrase and then ask for diagnosis of a
fine point of language law, would you? No, I'm sure you
wouldn't have done anything *that* silly -- but then again,
it's pretty silly to torment your compilers with syntax
errors and then try to make sense of the results ...)

--
Er*********@sun.com

Nov 14 '05 #3
Paul Steckler wrote:
Here's some code that's giving me differing results,
depending on the compiler. cat foo.c #include <stdio.h>

typedef struct Foo {
int A, B;
} Foo;

int main() {
int A;
Foo foo;

A = 57;
foo.A = 42;

A = foo.A += A; // crucial statement

printf("A = %d\tfoo.A = %d\n", A, foo.A);

return 0;
}
gcc -Wall -std=c99 -pedantic -o foo foo.c
./foo A = 99 foo.A = 99
Using Cygwin gcc 3.3.3, I get 99 for both A and foo.A.
Using a different compiler, I get 84 for both A and foo.A.

The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?


Nope.
Nov 14 '05 #4
Eric Sosman wrote:
Paul Steckler wrote:
Here's some code that's giving me differing results, depending on the
compiler.

[includes omitted]

typedef foo {
int A,B;
} FOO;

int main() {
int A;
FOO foo;

A = 57;
foo.A = 42;

A = foo.A += A; /* crucial statement */

printf("A = %d; foo.A = %d\n",A,foo.A);

return 0;
}

Using Cygwin gcc 3.3.3, I get 99 for both A and foo.A.
Using a different compiler, I get 84 for both A and foo.A.

The result given by gcc is what I expected. Is there any ambiguity in
the semantics of the crucial statement here?

The statement is worse than ambiguous; it's meaningless
because it resides in a non-C source. Once the compiler
issues the required diagnostic it's free to go ahead and
translate the non-C program, but the Standard no longer
governs what happens when and if the program is executed.

Things would have been different if there had been a
`struct' or `union' keyword right after the `typedef', or
if `foo' had been #define'd as `struct' or `union' itself.
Had that been the case, there would have been no ambiguity,
the Standard would have remained in force, and both outputs
would have been 99.

But as the code stands, both compilers are "right" --
provided they've issued that diagnostic, of course.

(You *did* cut and paste the actual code, didn't you?
Surely you wouldn't have been foolhardy enough to post an
inaccurate paraphrase and then ask for diagnosis of a
fine point of language law, would you? No, I'm sure you
wouldn't have done anything *that* silly -- but then again,
it's pretty silly to torment your compilers with syntax
errors and then try to make sense of the results ...)

Eric Sosman is trying to be clever and funny.
He is saying that the code above is *not* even a C program
and that subscribers to comp.lang.c should not be expected
to make any intelligent comments about it,

Paul Steckler should have tested and included a complete
standard compiant program that we could test ourselves.
I "guessed" at what Paul meant in my reply to his original posting
but I would *not* expect any other subscriber to do the same.
Nov 14 '05 #5
Eric Sosman wrote:
You *did* cut and paste the actual code, didn't you?


OK, you got me. My error, and my apologies.

Here's the full program I tried (cut and paste, albeit in two gulps).
It contains a bit more code:

--
#include <stdio.h>

typedef struct _s_ {
unsigned int A,B;
} ST;

int main(int argc,char **argv) {
ST st;
unsigned long A,B;

st.A = 42;
st.B = 18;

A = 57;
B = 39;

// clever code
A = st.A += A;
B = st.B += B;

puts("Clever code fails");
printf("A and st.A should be %d; A = %d, st.A = %d\n",42 +
57,A,st.A);
printf("B and st.B should be %d; B = %d, st.B = %d\n",18 +
39,B,st.B);

// same init values
st.A = 42;
st.B = 18;

A = 57;
B = 39;

// unclever version sequentializes assignments
st.A += A;
A = st.A;
st.B += B;
B = st.B;

puts("Unclever code succeeds");
printf("A and st.A should be %d; A = %d, st.A = %d\n",42 +
57,A,st.A);
printf("B and st.B should be %d; B = %d, st.B = %d\n",18 +
39,B,st.B);

return 0;
}
--

The other compiler was Green Hill Multi 4 for the PowerPC.
Green Hills has tentatively acknowledged the issue as a bug.

While I believe there's no ambiguity in the nested
assignments, can anyone cite relevant sections of
the C90 or C99 standards to support that belief?

-- Paul

Nov 14 '05 #6

On Wed, 6 Oct 2004 st***@ccs.neu.edu wrote:

Eric Sosman wrote:
You *did* cut and paste the actual code, didn't you?
OK, you got me. My error, and my apologies.


Yup, you /always/ need to give the actual code you're asking about.
Otherwise, the error could be anywhere... such as in the part you
forgot to include! (In this case, it wasn't... but it could have
been.)

typedef struct _s_ {
'_s_' is a terrible name for anything in C, because many names
beginning with an underscore are reserved for the implementation.
I don't think '_s_' itself is reserved, but in this case you could
have avoided the whole debate by leaving it blank.

typedef struct {
unsigned int A,B;
} ST;

int main(int argc,char **argv) {
ST st;
unsigned long A,B;
Learn to indent your code by putting spaces in front of certain
statements to indicate nesting. It'll save you many hassles in the
future. Also, note that 'argc' and 'argv' are not used here, so it
would be appropriate to write

int main(void)
{

instead.
st.A = 42;
st.B = 18;

A = 57;
B = 39;

// clever code
A = st.A += A;
B = st.B += B;


Both of these lines invoke undefined behavior, AFAICT. Look in
section "6.5.16 Assignment operators" of N869, and consider the
following valid interpretations of the line 'A = st.A += A;'

(1)
Sequence point
Compute st.A + A
Update value of object st.A with that result
Update value of object A with value of st.A
Sequence point

(2)
Sequence point
Compute result of st.A += A (which is st.A + A)
Update value of object A with that result
Compute st.A + A
Update value of object st.A with that result
Sequence point

Now, I'm not a (very good) language lawyer, but I would certainly
consider this undefined behavior, rather than a compiler bug. It's
definitely a construct that a good programmer would never use in
serious code, though, so I can't say I find it a life-or-death issue. ;-)

-Arthur
Nov 14 '05 #7
Arthur J. O'Dwyer wrote:
Learn to indent your code by putting spaces in front of certain
statements to indicate nesting. It'll save you many hassles in the
future.
Ummm, blame that one on Google groups beta submission form.
My code was beautifully indented.
It's definitely a construct that a good programmer would never use in
serious code, though, so I can't say I find it a life-or-death issue.

;-)
The issue was discovered when compiling the OpenSSL sources.

-- Paul

Nov 14 '05 #8
Dave Vandervies wrote:
typedef foo { ^^^^^^^^^^^^^^^

Should probably be

typedef struct foo
The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?

I don't see any.


Maybe not in the crucial statement, but see above. :)

--
Thomas.
Nov 14 '05 #9
On Wed, 6 Oct 2004 21:33:32 -0400 (EDT), in comp.lang.c , "Arthur J.
O'Dwyer" <aj*@nospam.andrew.cmu.edu> wrote:
'_s_' is a terrible name for anything in C, because many names
beginning with an underscore are reserved for the implementation.
I don't think '_s_' itself is reserved, but in this case you could
have avoided the whole debate by leaving it blank.


7.1.3 Reserved identifiers
Each header declares or defines all identifiers listed in its associated
subclause, and optionally declares or defines identifiers listed in its
associated future library directions subclause and identifiers which are
always reserved either for any use or for use as file scope identifiers.

- All identifiers that begin with an underscore and either an uppercase
letter or another underscore are always reserved for any use.

- All identifiers that begin with an underscore are always reserved for
use as identifiers with file scope in both the ordinary and tag name
spaces.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 14 '05 #10
In article <Pi***********************************@unix41.andr ew.cmu.edu>,
Arthur J. O'Dwyer <aj*@nospam.andrew.cmu.edu> wrote:

On Wed, 6 Oct 2004 st***@ccs.neu.edu wrote:
st.A = 42;
st.B = 18;

A = 57;
B = 39;

// clever code
A = st.A += A;
B = st.B += B;


Both of these lines invoke undefined behavior, AFAICT. Look in
section "6.5.16 Assignment operators" of N869, and consider the
following valid interpretations of the line 'A = st.A += A;'

(1)
Sequence point
Compute st.A + A
Update value of object st.A with that result
Update value of object A with value of st.A
Sequence point

(2)
Sequence point
Compute result of st.A += A (which is st.A + A)
Update value of object A with that result
Compute st.A + A
Update value of object st.A with that result
Sequence point

Now, I'm not a (very good) language lawyer, but I would certainly
consider this undefined behavior, rather than a compiler bug.


Nope. Assignment operators associate right to left, so this parses as
`A = (st.A += A)'. The `st.A+=A' part has a well-defined value that
depends only on the old values of A and st.A, and that's what should be
stored in A (and also st.A).
(The value of A can't be accessed after it's been updated, since the
old value is required to determine the new value.)

So the order of operations is:
sequence point
compute st.A+A (required for both of the following)
unordered
{
update value of st.A with result
update value of A with result
}
sequence point
It's
definitely a construct that a good programmer would never use in
serious code, though, so I can't say I find it a life-or-death issue. ;-)


I'd say that depends on what the serious code is supposed to be doing.
Generally the only good reason to use expressions with multiple
side-effects is if they maintain an invariant of some kind (the canonical
example is `foo[i++]=value', to maintain the invariant `i indexes the
first empty position in foo[]'); if that's what's happening here, then
it makes sense to keep it all in one expression.
On the other hand, given that it appears to be an easy way to work around
a compiler bug, that's a good reason to split it up here.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
[It] makes you look like a pathetic wannabe who wants to emulate the flames
posted by the adults, but doesn't understand the logic or the value system
behind them. --Billy Chambless in comp.lang.c
Nov 14 '05 #11
On Wed, 06 Oct 2004 20:25:34 -0700, steck wrote:
Arthur J. O'Dwyer wrote:
Learn to indent your code by putting spaces in front of certain
statements to indicate nesting. It'll save you many hassles in the
future.
Ummm, blame that one on Google groups beta submission form.
My code was beautifully indented.


If the Google groups submission form is eating initial space characters,
it's buggy and you'd do well to get your own news client and find a free
server (if your ISP doesn't offer one).

Plus, a good news client implements killfiling and other useful functions
that, so far as I can tell, are missing from the Google web-based Usenet
interface.
It's definitely a construct that a good programmer would never use in
serious code, though, so I can't say I find it a life-or-death issue.
;-) The issue was discovered when compiling the OpenSSL sources.


Not good. I would regard this as a bug in the sources, and I'd be tempted
to send in a patch to the maintainers. It's bad practice even if gcc does
the expected thing when it encounters it, and in a security-conscious
application like OpenSSL that is inexcusable.

-- Paul


Nov 14 '05 #12
Dave Vandervies wrote:
So the order of operations is:
sequence point
compute st.A+A (required for both of the following)
unordered
{
update value of st.A with result
update value of A with result
}
sequence point
This corresponds with my understanding, indicating that
the result of the statement is determinate.
It's
definitely a construct that a good programmer would never use in
serious code, though, so I can't say I find it a life-or-death

issue. ;-)
I'd say that depends on what the serious code is supposed to be

doing.

Because it's used in OpenSSL, it's protecting your credit card number,
if not your life. :-)
-- Paul
--
Paul Steckler, PhD
NGIT/FNMOC
Monterey, CA

Nov 14 '05 #13
dj******@csclub.uwaterloo.ca (Dave Vandervies) wrote:
Paul Steckler <st***@ccs.neu.edu> wrote:
Here's some code that's giving me differing results, depending
on the compiler.

int A;
FOO foo;
A = 57;
foo.A = 42;
A = foo.A += A; /* crucial statement */


Is there any ambiguity in the semantics of the crucial
statement here?

I don't see any.

The first suspect is invoking undefined behavior by both changing
an object's value and using an its value for something other than
calculating the new value to be stored between sequence points (N869
6.5#2), but you're not doing that here.


I disagree. Assignment operators do not create sequence points.
There is clearly a read and a write of A with no intervening
sequence point. The only question is whether this case is
covered by the provision in 6.5#2 (see below for more
discussion of this).

If the statement were: A = B += C, then the shortest set
of operations is clearly:
- add C into B
- write B to A
But some CPUs do not even have an instruction for
(add contents of one address into contents of another address)
and those that do, may find it less optimal than register
accumulation.
So do the steps in that order a compiler might have to go:
- write B to register R
- add C into R
- write R to B
- write R to A
If A is a register then the optimal set of steps would be:
- write B to A
- add C into A
- write A to B
(clearly better than the 4-step sequence above).

This way would result in A = 84 and foo.A = 84.
For the OP, we could try and see if that is what the compiler
did:
1) What is the value of 'd': d = (A = foo.A += A);
2) Does it make a difference if you force A to not be a register:
int *p = &A; (before the assignment)
3) Does it make a difference if foo.A is a register?
(to do this you probably will need to use a
"register int b;" instead of foo.A)
4) Can you paste the assembly generated for the assignment.

Now, I don't fully grok the wording of the relevant
standard passage:

[#2] Between the previous and next sequence point an object
shall have its stored value modified at most once by the
evaluation of an expression. Furthermore, the prior value
shall be accessed only to determine the value to be
stored.60)

But it seems to me that A is being read to determine the
value of foo.A, not to determine the new value of A.
Therefore it is UB.
Nov 14 '05 #14
In article <84**************************@posting.google.com >,
Old Wolf <ol*****@inspire.net.nz> wrote:
dj******@csclub.uwaterloo.ca (Dave Vandervies) wrote:
Paul Steckler <st***@ccs.neu.edu> wrote:
>Here's some code that's giving me differing results, depending
>on the compiler.
> int A;
> FOO foo;
> A = 57;
> foo.A = 42;
> A = foo.A += A; /* crucial statement */


Is there any ambiguity in the semantics of the crucial
statement here?

I don't see any.

The first suspect is invoking undefined behavior by both changing
an object's value and using an its value for something other than
calculating the new value to be stored between sequence points (N869
6.5#2), but you're not doing that here.


I disagree. Assignment operators do not create sequence points.


There's no need for them to do so here.
There is clearly a read and a write of A with no intervening
sequence point. The only question is whether this case is
covered by the provision in 6.5#2 (see below for more
discussion of this).
[reordered]Now, I don't fully grok the wording of the relevant
standard passage:

[#2] Between the previous and next sequence point an object
shall have its stored value modified at most once by the
evaluation of an expression. Furthermore, the prior value
shall be accessed only to determine the value to be
stored.60)

But it seems to me that A is being read to determine the
value of foo.A, not to determine the new value of A.
Therefore it is UB.
The value assigned to A is the value of the expression `foo.A+=A'.
This value depends on the value read from A, so the access to A is used
to determine the value stored in A. The fact that the read access to
A is also used to determine the new value of foo.A (and that this value
is the same as the new value of A) is incidental.
If the statement were: A = B += C, then the shortest set
of operations is clearly:
- add C into B
- write B to A
But some CPUs do not even have an instruction for
(add contents of one address into contents of another address)
and those that do, may find it less optimal than register
accumulation.
So do the steps in that order a compiler might have to go:
- write B to register R
- add C into R
- write R to B
- write R to A
If A is a register then the optimal set of steps would be:
- write B to A
- add C into A
- write A to B
(clearly better than the 4-step sequence above).
....except that if A and C are the same register it gives incorrect
results, by erroneously clobbering the old value of A/C before saving it.

If the code were:
D = A + B + C
would you accept this:
-Copy A to D
-Add B into D
-Add C into D
? Would your answer change if B and D were the same register?

This way would result in A = 84 and foo.A = 84.
For the OP, we could try and see if that is what the compiler
did:
1) What is the value of 'd': d = (A = foo.A += A);
2) Does it make a difference if you force A to not be a register:
int *p = &A; (before the assignment)
3) Does it make a difference if foo.A is a register?
(to do this you probably will need to use a
"register int b;" instead of foo.A)
4) Can you paste the assembly generated for the assignment.


The results of this would be helpful in demonstrating that there's a
compiler bug, but it's still a compiler bug.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
I'm surprised you can make a living as a programmer or in any other field
which requires mental aptitude and the ability to communicate.
--Andrew Dalke roasts a troll in comp.lang.scheme
Nov 14 '05 #15

On Thu, 7 Oct 2004, Dave Vandervies wrote:
Arthur J. O'Dwyer <aj*@nospam.andrew.cmu.edu> wrote:
On Wed, 6 Oct 2004 st***@ccs.neu.edu wrote:

// clever code
A = st.A += A;
B = st.B += B;
Both of these lines invoke undefined behavior, AFAICT. Look in
section "6.5.16 Assignment operators" of N869, and consider the
following valid interpretations of the line 'A = st.A += A;'

(1)
Sequence point
Compute st.A + A
Update value of object st.A with that result
Update value of object A with value of st.A
Sequence point

(2)
Sequence point
Compute result of st.A += A (which is st.A + A)
Update value of object A with that result
Compute st.A + A
Update value of object st.A with that result
Sequence point

Now, I'm not a (very good) language lawyer, but I would certainly
consider this undefined behavior, rather than a compiler bug.


Nope. Assignment operators associate right to left, so this parses as
`A = (st.A += A)'. The `st.A+=A' part has a well-defined value that
depends only on the old values of A and st.A, and that's what should be
stored in A (and also st.A).


Correct, except for the UB part.
(The value of A can't be accessed after it's been updated, since the
old value is required to determine the new value.)
Chapter and verse, please.
So the order of operations is:
sequence point
compute st.A+A (required for both of the following)
unordered
{
update value of st.A with result
update value of A with result
This is /obviously/ wrong, since by the second "result" you either mean
the result of st.A+A, which is /not/ necessarily the value stored in A (it
gets the result of st.A+=A, which may have a different type and even a
different value, depending on the types of A and st.A); or else you mean
the result of updating st.A with st.A+A, in which case you're mistaken
about the "unordered" part.
}
sequence point


-Arthur
Nov 14 '05 #16
In article <Pi**********************************@unix49.andre w.cmu.edu>,
Arthur J. O'Dwyer <aj*@nospam.andrew.cmu.edu> wrote:

On Thu, 7 Oct 2004, Dave Vandervies wrote:
Arthur J. O'Dwyer <aj*@nospam.andrew.cmu.edu> wrote:
On Wed, 6 Oct 2004 st***@ccs.neu.edu wrote:

// clever code
A = st.A += A;
B = st.B += B;

Both of these lines invoke undefined behavior, AFAICT. Look in
section "6.5.16 Assignment operators" of N869, and consider the
following valid interpretations of the line 'A = st.A += A;'

(1)
Sequence point
Compute st.A + A
Update value of object st.A with that result
Update value of object A with value of st.A
Sequence point

(2)
Sequence point
Compute result of st.A += A (which is st.A + A)
Update value of object A with that result
Compute st.A + A
Update value of object st.A with that result
Sequence point

Now, I'm not a (very good) language lawyer, but I would certainly
consider this undefined behavior, rather than a compiler bug.
Nope. Assignment operators associate right to left, so this parses as
`A = (st.A += A)'. The `st.A+=A' part has a well-defined value that
depends only on the old values of A and st.A, and that's what should be
stored in A (and also st.A).


Correct, except for the UB part.
(The value of A can't be accessed after it's been updated, since the
old value is required to determine the new value.)


Chapter and verse, please.


"Can't be" is perhaps too strong. The implementation is required to
produce code that acts as if it isn't, though.

(All quotes from N869)

6.5.16#1 gives the syntax for assignment operators:
assignment-expr:
conditional-expr
unary-expr assignment-operator assignment-expr

assignment-operator: one of
= *= /= %= += -= <<= >>= &= ^= |=

So `st.A+=A' is the right operand of '=' in the expression `A=st.A+=A'.

6.5.16#3 (semantics of assignment operators):
[#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.

So we're storing a value in A. What's that value?

6.5.16.1#2 (semantics for simple assignment):
[#2] In simple assignment (=), the value of the right
operand is converted to the type of the assignment
expression and replaces the value stored in the object
designated by the left operand.

So it's the value of the right operand, `st.A+=A', converted appropriately
(in this case, no conversion, since both st.A and A are ints).
What's that value?

6.5.16.2#3 (semantics for compound assignment):
[#3] A compound assignment of the form E1 op= E2 differs
from the simple assignment expression E1 = E1 op (E2) only
in that the lvalue E1 is evaluated only once.

So (with a stop back at 6.5.16#3 where the value of the expression is
defined to be the value stored in the left operand) 6.5.16.2#3 applies:
It's the new value of st.A, which is the value of `st.A + (A)' evaluated
before the values of the objects are updated[%], converted appropriately.

So the value stored in A is required to be the sum of the old value of
st.A and the old value of A, converted appropriately (to the type of
st.A and then to the type of A).

[%] I'm assuming without proof that `a=a+b' requires that the old value
of a be used as an operand to the addition. If you really want me
to, I can dig up chapter and verse for this too, but hopefully at
least this much is clear.

None of this violates 6.5#2:
[#2] Between the previous and next sequence point an object
shall have its stored value modified at most once by the
evaluation of an expression. Furthermore, the prior value
shall be accessed only to determine the value to be
stored.60) *

The prior values of both A and st.A are accessed only to determine the
value to be stored in st.A, and the value to be stored in A is determined
directly from this (and indirectly from the old values) without further
access to the objects.
So since everything can be reduced to storing well-defined values into
objects, and the non-store accesses are used only to determine those
values to be stored, the entire expression is well-defined and has
well-defined side effects.

So the order of operations is:
sequence point
compute st.A+A (required for both of the following)
unordered
{
update value of st.A with result
update value of A with result


This is /obviously/ wrong, since by the second "result" you either mean
the result of st.A+A, which is /not/ necessarily the value stored in A (it
gets the result of st.A+=A, which may have a different type and even a
different value, depending on the types of A and st.A);


In the code under discussion, both were ints, so no conversions were
necessary. But since we like pedantic nitpickery here:

The order of operations is:
sequence point
compute st.A+A (call it "result", for notational convenience)
unordered
{
store "result", converted appropriately, into st.A
store "result", converted appropriately, into A
(Note that this involves two (possibly no-op) conversions, to type
of st.A and then to type of A)
}
sequence point

or else you mean
the result of updating st.A with st.A+A, in which case you're mistaken
about the "unordered" part.


I'm trying and failing to see how that interpretation could be considered
sensible enough to not be immediately discarded in favor of the more
sensible alternative, even by the most pedantic nitpicker.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
This way we have to exchange insults by proxy, and its a self-moderating
mechanism since people rapidly get bored being the go-between.
--Mark McIntyre in comp.lang.c
Nov 14 '05 #17
st***@ccs.neu.edu (Paul Steckler) wrote in message news:<9b*************************@posting.google.c om>...
Here's some code that's giving me differing results, depending
on the compiler.
<snip>
A = foo.A += A; /* crucial statement */

<snip>
The result given by gcc is what I expected. Is there any
ambiguity in the semantics of the crucial statement here?


No, there's not. 6.5.16:

3 An assignment operator stores a value in the object designated
by the left operand. An assignment expression has the value of
the left operand after the assignment, but is not an lvalue.
The type of an assignment expression is the type of the left
operand unless the left operand has qualified type, in which
case it is the unqualified version of the type of the left
operand. The side effect of updating the stored value of the
left operand shall occur between the previous and the next
sequence point.
The value of the += in 'foo.A += A' is well defined, even though the
state of the foo.A object itself is indeterminite until the next
sequence point. It is the value of the +=, not the value of foo.A,
that should be stored in A. This may be where the compiler gets it
wrong.

As you noted in another post, this is a compiler bug, and from the
looks of it, a relatively severe one. Hmmm.
Mark F. Haigh
mf*****@sbcglobal.net
Nov 14 '05 #18
dj******@csclub.uwaterloo.ca (Dave Vandervies) wrote in message news:<ck**********@rumours.uwaterloo.ca>...
In article <Pi***********************************@unix41.andr ew.cmu.edu>,
Arthur J. O'Dwyer <aj*@nospam.andrew.cmu.edu> wrote:

On Wed, 6 Oct 2004 st***@ccs.neu.edu wrote:

st.A = 42;
st.B = 18;

A = 57;
B = 39;

// clever code
A = st.A += A;
B = st.B += B;


Both of these lines invoke undefined behavior, AFAICT. Look in
section "6.5.16 Assignment operators" of N869, and consider the
following valid interpretations of the line 'A = st.A += A;'

(1)
Sequence point
Compute st.A + A
Update value of object st.A with that result
Update value of object A with value of st.A
Sequence point

(2)
Sequence point
Compute result of st.A += A (which is st.A + A)
Update value of object A with that result
Compute st.A + A
Update value of object st.A with that result
Sequence point

Now, I'm not a (very good) language lawyer, but I would certainly
consider this undefined behavior, rather than a compiler bug.


Nope. Assignment operators associate right to left, so this parses as
`A = (st.A += A)'. The `st.A+=A' part has a well-defined value that
depends only on the old values of A and st.A, and that's what should be
stored in A (and also st.A).
(The value of A can't be accessed after it's been updated, since the
old value is required to determine the new value.)


What I am unsure about is what the following means:

"The order of evaluation of the operands is unspecified.
If an attempt is made to modify the result of an assignment
operator or to access it after the next sequence point,
the behavior is undefined."

Which is 6.5.16#4

How can you modify the result of an assignment operator?
I don't think this is possible.

e.g. int i = 10;
int b;

b = ++i = i;

is how I interpret that.

additionally,
"to access the result of an assignment
/after/ the next sequent point is undefined."

That doesn't seem to make any sense.

e.g. int i = 10;
<before next sequence point>
i = i + 10;
<next sequence point>
i++; /* accessed the result of an
assignment after the next sequence point */
also, while on the topic of sequence points,

what happens with something like this:

foo = a + func(++a); ?
Nov 14 '05 #19
Dave Vandervies wrote:
In article <84**************************@posting.google.com >,
Old Wolf <ol*****@inspire.net.nz> wrote:

[snip]

There is really nothing to discuss.

int i = 3;
i = i + 1;

is valid. There is no real difference between the above
and code posted by the OP.

--
Thomas.
Nov 14 '05 #20
In article <2s*************@uni-berlin.de>,
Thomas Stegen <th***********@gmail.com> wrote:
There is really nothing to discuss.

int i = 3;
i = i + 1;

is valid. There is no real difference between the above
and code posted by the OP.


Chapter and verse?

(You could cheat and just point to my post replying to Arthur's request
for chapter and verse. But, based on the discussion we've seen, it's
obviously not immediately and universally clear that this is the case.)
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
[The BOFHlet is] Gonna be a danger to herself and others, just like mom and
dad.
--Dan Birchall in the scary devil monastery
Nov 14 '05 #21
In article <news:2d**************************@posting.google. com>
j0mbolar <j0******@engineer.com> wrote, in part:
What I am unsure about is what the following means:

"The order of evaluation of the operands is unspecified.
If an attempt is made to modify the result of an assignment
operator or to access it after the next sequence point,
the behavior is undefined."

Which is 6.5.16#4

How can you modify the result of an assignment operator?


I believe this refers to tricks like this:

struct S { int a[10]; };

struct S s1, s2;
int *p;

p = (s1 = s2).a;
p[2] = 42; /* presumably, this violates 6.5.16#4 */

This "accesses it after a sequence point" *and* modifies it; to
just modify it, all in one swell foop as it were, we might write:

(s1 = s2).a[2] = 42;

eliminating the variable "p" entirely.
--
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.
Nov 14 '05 #22

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

Similar topics

4
by: Jacek Generowicz | last post by:
I am dealing with an application which reads in configurations by calling (a wrapper around) execfile. Any configuration file may itself execfile other configuration files in the same manner. I...
3
by: bearophileHUGS | last post by:
The current version of ShedSkin (http://shedskin.sourceforge.net/ experimental Python to C++ compiler) is rather alpha, and the development work is focused on debugging and implementing some more...
0
by: ciaran.mchale | last post by:
I used Google to find information about JAXB 2.0 and I ended up downloading a document called "The Java Architecture for XML Binding (JAXB) 2.0: Proposed Final Draft September 30, 2005". ...
30
by: Matt | last post by:
Does clock_t clock() measure real time or process time? Unless I have missed something, Stroustrup's treatment in TC++PL (section D.4.4.1) is none too clear on that question. Is clock()...
17
by: Brian Blais | last post by:
Hello, I have a couple of classes where I teach introductory programming using Python. What I would love to have is for the students to go through a lot of very small programs, to learn the...
3
by: subramanian100in | last post by:
I have tried the following in VC++ 2005 Express Edition and g++ in Linux. Consider the class class my_complex { public: my_complex(double r, double i = 10.0) : re(r), im(i) { }...
2
by: subramanian100in | last post by:
Consider the program #include <iostream> using namespace std; void fn(const char * str, char x = 'Y') { cout << "from fn(const char *, char) - " << str << endl; return;
4
by: abendstund | last post by:
Hi, I have the following code and trouble with ambiguity due to operator overloading.. The code is also at http://paste.nn-d.de/441 snip>>
6
by: akva | last post by:
Hi All, what's the exact semantics of the |= operator in python? It seems that a |= d is not always equivalent to a = a | d For example let's consider the following code: def foo(s): s = s...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.