Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does this program have undefined behavior?

3 views
Skip to first unread message

nit...@gmail.com

unread,
Nov 15, 2009, 1:36:08 AM11/15/09
to
#include <stdio.h>
int g = 1;

int func_2()
{
g = 2;
return 3;
}

int main()
{
int *l = &g;
*l = func_2(); /* LHS evaluates to g, and
RHS writes to g */
printf("g = %d\n", g);
return 0;
}

My colleague and I had a lengthy discussion, and nobody can be
convinced by the other. The question is: can g ever gets the value of
2 at the end of the program?

Appreciate your expert thoughts...

Jason

James Dow Allen

unread,
Nov 15, 2009, 3:48:22 AM11/15/09
to
On Nov 15, 1:36 pm, "nits...@gmail.com" <nits...@gmail.com> wrote:
> [snip] ; [snip]

Semi-colon. Less well known, perhaps, than the Comma "sequence point"
but it also serializes.

> The question is: can g ever gets the value of
> 2 at the end of the program?

No. And BTW, we don't use "gets".

> Appreciate your expert thoughts...

I'm no expert and am probably wrong again! :-)

James

Nick

unread,
Nov 15, 2009, 3:51:11 AM11/15/09
to
"nit...@gmail.com" <nit...@gmail.com> writes:

I'm not an expert, particularly on things like this. My feeling tends
to be "if this is likely to lead people into lengthy discussions as to
whether it's a bug or not, then don't do it unless you really, really
need to - and then comment it!".

But I'm pretty sure that this is defined. func_2 is executed, changing
g and returning 3. Then this is written into g.

The only reason I'm tentative at all is that I remember a long
discussion from a long time ago involving changing an array index that
turned out to be undefined.

Nick, confidently waiting to be proved wrong.
--
Online waterways route planner: http://canalplan.org.uk
development version: http://canalplan.eu

Keith Thompson

unread,
Nov 15, 2009, 4:10:49 AM11/15/09
to
"nit...@gmail.com" <nit...@gmail.com> writes:
> #include <stdio.h>
> int g = 1;
>
> int func_2()
> {
> g = 2;
> return 3;
> }
>
> int main()
> {
> int *l = &g;
> *l = func_2(); /* LHS evaluates to g, and RHS writes to g */
> printf("g = %d\n", g);
> return 0;
> }
>
> My colleague and I had a lengthy discussion, and nobody can be
> convinced by the other. The question is: can g ever gets the value of
> 2 at the end of the program?

Strictly speaking, I believe the program's behavior is undefined
because you wrote "int main()" rather than "int main(void)", but
I'm sure that's not what you had in mind. 8-)}

I don't believe doing the assignment through a pointer changes
anything. You could have dropped the declaration of l and written
g = func_2();
with the same effect.

This assigns the result of the function call to g. The assignment
cannot modify the value of g until after it's evaluated the
expression func_2(). During the evaluation of func_2(), g is set
to 2, then there's a sequence point, then the value 3 is returned.

So "g = 2" must be evaluated, and its side effect must occur,
before "return 3" is executed (because of the sequence point), and
"return 3" must be executed before g is modified by the assignment
(because it computes the value to be assigned).

Note that this reasoning does not apply to the classic "i = i++".
The value yielded by "i++" must be determined before the assignment
can modify i, but the side effect of "i++" can take place either
before or after the side effect of the assignment.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

nit...@gmail.com

unread,
Nov 15, 2009, 4:17:19 AM11/15/09
to
>
> No.  And BTW, we don't use "gets".
>

Sorry about that. This is actually the first question I ask here. :)

Richard Heathfield

unread,
Nov 15, 2009, 4:31:43 AM11/15/09
to
In <lneio0i...@nuthaus.mib.org>, Keith Thompson wrote:

<snip>



> Strictly speaking, I believe the program's behavior is undefined
> because you wrote "int main()" rather than "int main(void)", but
> I'm sure that's not what you had in mind. 8-)}

It probably isn't what K&R had in mind either, when they wrote K&R2
(which is based on ANSI C, i.e. C89). Perhaps you'd better take it up
with them? :-)

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

nit...@gmail.com

unread,
Nov 15, 2009, 4:27:12 AM11/15/09
to
Seems like an unanimous vote for "defined". But what if I tell you the
argument for "undefined" is this: at line "*l = func_2();", both RHS
and the whole assignment expression write to "g", and there is only
one sequence point, which is after ";". According to C99, it is
undefined to have more than one write to the same variable between one
sequence point and the next sequence point.

How would you argue against this?

Richard Heathfield

unread,
Nov 15, 2009, 4:35:01 AM11/15/09
to
In <9a4ac225-db13-481c...@m7g2000prd.googlegroups.com>,
nit...@gmail.com wrote:

>>
>> No. And BTW, we don't use "gets".
>>
>
> Sorry about that. This is actually the first question I ask here. :)

Just in case you don't gets it, he's just joking you around. Your
article had a minor typographical error, which nobody sane is
bothered about, but it happened to be the word "gets", which is also
the name of a C function that is generally agreed to be impossible to
use safely. (It is not universally agreed, for much the same reason
that it is not universally agreed that oxygen is a good thing for
humans to breathe. There's *always* somebody who disagrees...)

pete

unread,
Nov 15, 2009, 4:42:43 AM11/15/09
to

A function call is also a sequence point.

--
pete

Flash Gordon

unread,
Nov 15, 2009, 5:01:42 AM11/15/09
to

I believe you are correct that it is completely defined. My reasoning is
as follows...

There is a sequence point between the assignment in the function and the
return statement. There is also a sequence point on returning from the
function. Therefore there are sequence points between the assignment
inside the function and the assignment outside the function. Simplyfiy
the code to the following and it is still well defined...

#include <stdio.h>
int g = 1;

int func_2()
{
g = 2; /* Sequence point here */
return 3; /* Sequence point here */
}

int main()
{
g = func_2();


printf("g = %d\n", g);
return 0;
}

--
Flash Gordon

Flash Gordon

unread,
Nov 15, 2009, 5:07:34 AM11/15/09
to

That shows there is a sequence point, but it's not the important one.
The important one is the sequence point on returning from the function.
--
Flash Gordon

S R

unread,
Nov 15, 2009, 6:43:12 AM11/15/09
to
On Nov 15, 2:10 pm, Keith Thompson <ks...@mib.org> wrote:

> "nits...@gmail.com" <nits...@gmail.com> writes:
> > #include <stdio.h>
> > int g = 1;
>
> > int func_2()
> > {
> >    g = 2;
> >    return 3;
> > }
>
> > int main()
> > {
> >    int *l = &g;
> >    *l = func_2(); /* LHS evaluates to g, and RHS writes to g */
> >    printf("g = %d\n", g);
> >    return 0;
> > }
>
[snip]

>
> Strictly speaking, I believe the program's behavior is undefined
> because you wrote "int main()" rather than "int main(void)", but
> I'm sure that's not what you had in mind.  8-)}
>

[SR] May be, I am missing something, but I don't see why the code
invokes undefined behaviour.

From N1256 (I am aware that this is not the latest, but I think it is
sufficient for this discussion)

6.7.5.3 Function declarators (including prototypes)
"An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters"

Since int main(), in the code presented by the OP, is a definition, I
don't see any cause of undefined behaviour.

Also,
5.1.2.2.1 Program startup

" It shall be defined with a return type of int and with no
parameters "

( Although the example given is of the form int main(void), I am not
able to see how int main() does not satisfy the requirement stated
above. Also, things specified in the future language directions do not
apply here. It is *indeed* better to write int main (void), but int
main() is equally correct)


[snip]

--
SR

Joachim Schmitz

unread,
Nov 15, 2009, 7:48:22 AM11/15/09
to
S R wrote:
> On Nov 15, 2:10 pm, Keith Thompson <ks...@mib.org> wrote:
>> "nits...@gmail.com" <nits...@gmail.com> writes:
>>> #include <stdio.h>
>>> int g = 1;
>>
>>> int func_2()
>>> {
>>> g = 2;
>>> return 3;
>>> }
>>
>>> int main()
>>> {
>>> int *l = &g;
>>> *l = func_2(); /* LHS evaluates to g, and RHS writes to g */
>>> printf("g = %d\n", g);
>>> return 0;
>>> }
>>
> [snip]
>>
>> Strictly speaking, I believe the program's behavior is undefined
>> because you wrote "int main()" rather than "int main(void)", but
>> I'm sure that's not what you had in mind. 8-)}
>>
>
> [SR] May be, I am missing something, but I don't see why the code
> invokes undefined behaviour.
>
> From N1256 (I am aware that this is not the latest, but I think it is
> sufficient for this discussion)


It is not? AFAIK it is the latest valid Standard including all 3 existing
TCs.

Everything after that is drafts, I think.

Bye, Jojo

Ben Bacarisse

unread,
Nov 15, 2009, 8:03:34 AM11/15/09
to
"nit...@gmail.com" <nit...@gmail.com> writes:

There is one at the ; as you say (too late to matter) but there is
also one at the function call itself (too early to matter). The
important point it that are two more in func_2: one just after 2 is
assigned and another just before 3 is returned.

--
Ben.

Ben Bacarisse

unread,
Nov 15, 2009, 8:11:06 AM11/15/09
to
James Dow Allen <jdall...@yahoo.com> writes:

> On Nov 15, 1:36 pm, "nits...@gmail.com" <nits...@gmail.com> wrote:
>> [snip] ; [snip]
>
> Semi-colon. Less well known, perhaps, than the Comma "sequence point"
> but it also serializes.

; does not mean there is a sequence point. For example, there is no
sequence point in

break;

nor in

continue;

<snip>
--
Ben.

Keith Thompson

unread,
Nov 15, 2009, 11:15:25 AM11/15/09
to
S R <mbt...@gmail.com> writes:
> On Nov 15, 2:10 pm, Keith Thompson <ks...@mib.org> wrote:
[...]

>> Strictly speaking, I believe the program's behavior is undefined
>> because you wrote "int main()" rather than "int main(void)", but
>> I'm sure that's not what you had in mind.  8-)}
>
> [SR] May be, I am missing something, but I don't see why the code
> invokes undefined behaviour.
[...]

C99 5.1.2.2.1p1:

It shall be defined with a return type of int and with no

parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though
any names may be used, as they are local to the function in which
they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; or in some other implementation-defined manner.

with a footnote:

Thus, int can be replaced by a typedef name defined as int, or the
type of argv can be written as char ** argv, and so on.

My argument is that
int main() { /* ... */ }
is not equivalent to
int main(void) { /* ... */ }
and therefore is not covered.

The only difference between this program:
int main(void) { return 0; }
int func(void) { return main(42); }
and this program:
int main() { return 0; }
int func(void) { return main(42); }
is the void keyword in the declaration of main. The first requires a
diagnostic; the second does not. So they're not equivalent.

In practice, I'd be surprised to see any compiler that doesn't quietly
accept "int main()" (which is, of course, one possible consequence of
undefined behavior). And of course "int main(void)" is better style
anyway.

I should probably set up a web page with this argument so I can refer
to it rather than reconstructing the argument each time.

Seebs

unread,
Nov 15, 2009, 12:33:40 PM11/15/09
to

There is another sequence point. Look at func_2(). Notice that it has
a statement. The end of that statement is a sequence point. That sequence
point must be hit before the function returns its value. So, before func_2()
returns 3, there has been a sequence point after the modification of g.

-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

Seebs

unread,
Nov 15, 2009, 12:43:28 PM11/15/09
to
On 2009-11-15, Keith Thompson <ks...@mib.org> wrote:
> My argument is that
> int main() { /* ... */ }
> is not equivalent to
> int main(void) { /* ... */ }
> and therefore is not covered.

I'm pretty sure that they're "equivalent" in the relevant sense.

An identifier list declares only the identifiers of the parameters of
the function. An empty list in a function declarator that is part of a


definition of that function specifies that the function has no

parameters.

The special case of an unnamed parameter of type void as the only item
in the list specifies that the function has no parameters.

It seems to me that these are the same definition. There are differences
elsewhere, but they are still equivalent.

In short, I think your argument is good, except that I believe "equivalent"
doesn't quite mean the same thing as "identical". Consider:

int main(int argc, char **argv) {
return argc != 1;
}
vs
int main(int intArgumentCount, char **arrayArrayArgumentVector) {
return argc != 1;
}

One of these requires a diagnostic, so clearly the two declarations are
not equivalent. :) (That said, note that the standard explicitly mentions
that the names are local variables and don't matter.)

Basically, there's a distinction to be made between "make the same
specification of the function" and "be precisely identical in all ways
including information available to the compiler".

Barry Schwarz

unread,
Nov 15, 2009, 12:59:31 PM11/15/09
to
On Sat, 14 Nov 2009 22:36:08 -0800 (PST), "nit...@gmail.com"
<nit...@gmail.com> wrote:

>#include <stdio.h>
>int g = 1;
>
>int func_2()
>{
> g = 2;
> return 3;
>}
>
>int main()
>{
> int *l = &g;
> *l = func_2(); /* LHS evaluates to g, and
>RHS writes to g */
> printf("g = %d\n", g);
> return 0;
>}
>
>My colleague and I had a lengthy discussion, and nobody can be
>convinced by the other. The question is: can g ever gets the value of
>2 at the end of the program?

No. There is a sequence point at the end of the first statement in
func2. There is also a sequence point when func2 returns prior the
returned value being assigned to *l.

This assumes you are not playing word games because at the end of the
program g ceases to exist and questions about its value become
metaphysical.

--
Remove del for email

S R

unread,
Nov 15, 2009, 1:17:49 PM11/15/09
to
On Nov 15, 9:15 pm, Keith Thompson <ks...@mib.org> wrote:
> S R <mbt...@gmail.com> writes:
> > On Nov 15, 2:10 pm, Keith Thompson <ks...@mib.org> wrote:
> [...]
> >> Strictly speaking, I believe the program's behavior is undefined
> >> because you wrote "int main()" rather than "int main(void)", but
> >> I'm sure that's not what you had in mind.  8-)}
>
> > [SR] May be, I am missing something, but I don't see why the code
> > invokes undefined behaviour.
>
> [...]
>
> C99 5.1.2.2.1p1:

[snip CV]

{SR] I had quoted this in my reply earlier. So this is not what
I missed.

> My argument is that
>     int main() { /* ... */ }
> is not equivalent to
>     int main(void) { /* ... */ }
> and therefore is not covered.
>

[SR] This where I think I disagree with you. From 6.7.5.3 Function
declarators (including prototypes) ( I'll quote again),

6.7.5.3 Function declarators (including prototypes)
"An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters"

Now, int main(){ /**/}, here, satisfies the above stated rule. So, main
() has no parameters. ---> (1)

Also,

5.1.2.2.1 Program startup

" It shall be defined with a return type of int and with no

^^^^^^^
parameters "
^^^^^^^^^^

(I intentionally ignore the example provided in the standard. The
example might include a void, but there is no wording in the
standard to push the use of void in the definition)

From (1), I conclude that int main(){} satisfies the above rule. So, I
see no omission to make the case for int main(){} to be undefined.

[snip]

--
SR

James Dow Allen

unread,
Nov 15, 2009, 1:29:43 PM11/15/09
to
On Nov 15, 8:11 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:

foo(a++ + a++)
gives undefined behavior; one could say that's because a needed
sequence point is missing. In this way, the concept "sequence
point" becomes meaningful.

Is there an example program where saying " 'continue;' lacks
a sequence point" is meaningful? That is, where the same
program could give different results *because* of that "missing"
sequence point? I can't think of one; maybe I'm lacking
imagination.

James

Ben Bacarisse

unread,
Nov 15, 2009, 2:14:22 PM11/15/09
to
James Dow Allen <jdall...@yahoo.com> writes:

I can't either or I would have included one! I don't think there is
one. My point was only about how C is specified.

--
Ben.

Malcolm McLean

unread,
Nov 15, 2009, 3:23:05 PM11/15/09
to

"Richard Heathfield" <r...@see.sig.invalid> wrote in message

>(It is not universally agreed, for much the same reason
> that it is not universally agreed that oxygen is a good thing for
> humans to breathe. There's *always* somebody who disagrees...)
>
Oxydative stress.

Then if we all used fluorine instead of oxygen for our redox reactions which
sustain life, the fluorine would be considerably more efficient, and food
would go further. So we'd need less farmland and the environment would
prosper.

Keith Thompson

unread,
Nov 15, 2009, 4:22:12 PM11/15/09
to

That's an interesting argument. However, the definitions that you
intentionally ignored are not examples. There are numerous examples
in the standard, and they're specifically marked as such; these are
not.

Quoting the standard yet again (not to imply that you missed anything,
just to keep the context near the commentary):

[...] It shall be defined with a return type of int and with no
parameters:


int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though
any names may be used, as they are local to the function in which
they are declared):
int main(int argc, char *argv[]) { /* ... */ }

or equivalent;9) or in some other implementation-defined manner.

If the second definition were to be ignored, we'd have no way to
know the types of the two parameters; the fact that they're int
and char*[] (or char**) is only stated in the definition.

So the standard doesn't just say that main can be defined with
a return type of int and no parameters (which "int main()" would
satisfy); it specifies *how* it can be defined with a return type
of int and no parameters ("int main(void)" or equivalent).

The fact that:

The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.

(C99 6.11.6) doesn't directly bear on the issue, since old-style
declarators are still fully part of the language. But it might
suggest that, if this issue is going to be resolved, it's more
likely to be made irrelevant by dropping old-style declarators
from the language than by actually settling the issue of whether
"int main()" is equivalent to "int main(void)".

Keith Thompson

unread,
Nov 15, 2009, 4:41:01 PM11/15/09
to

Another interesting argument. I haven't changed my mind, but I'm
considering it.

It's not obvious what the "relevant sense" of "equivalent" really is.

One counterargument I thought of is this: Suppose a compiler uses a
different calling sequence for
int foo(void) { /* ... */ }
than for
int foo() { /* ... */ }
There might be good reasons for doing so; the latter might pass
additional information for error checking (to detect calls whose
behavior is undefined) while the former doesn't need to, since any
such errors will be caught at compile time. The standard already
requires the calling environment to support two different calling
sequences for main; it doesn't require a third.

But I think that argument falls apart because an implementation is
already required to be able to call either function without knowing
its type. The following, as far as I can tell, is strictly
conforming:

#include <stdio.h>

int foo(void) {
puts("void foo(void)");
return 0;
}

int bar() {
puts("void bar()");
return 0;
}

int main(void) {
int (*ptr)();
ptr = foo;
ptr();
ptr = bar;
ptr();
return 0;
}

and 6.7.5.3 seems to say that the types of foo and bar are compatible.

So I think the argument in favor of "int main()"'s behavior being
defined is that "equivalent" means equivalent with respect to the
definition itself, not to its impact on code outside the definition.
And I'm still not convinced. I still think it's not equivalent,
because it can affect the legality of other code in the same
translation unit.

Seebs

unread,
Nov 15, 2009, 6:42:10 PM11/15/09
to

Hmmmm.

foo_s.h:
struct foo { int x; };

foo_f.h:
int use_foo(struct foo *a);

bar.c:
#include "foo_s.h"
#include "foo_f.h"

int main(void) {
struct foo x = { 0 };
use_foo(&x);
}

foo.c:
#include "foo_s.h"
struct bar { int x; };
extern int use_foo(struct bar *b) {
return b.x;
}

Common initial sequence says this should work, I think.

Now, consider the choice of whether to declare use_foo that way,
or declare it as:

#include "foo_f.h";
extern int use_foo(struct foo *a) {
return a.x;
}

And consider another function, in foo.c:

void dummy(void) {
struct foo z = { 0 };
use_foo(&z);
}

Obviously, which way you declare use_foo affects whether dummy() is
valid or not -- but I don't think it affects whether main() in bar.c
is valid or not, because all that's at issue is whether the arguments
are compatible, and the structs in question have a common initial
sequence.

So I think they're equivalent definitions, even though one of them
clearly breaks other code in the same translation unit.

James Dow Allen

unread,
Nov 16, 2009, 12:12:37 AM11/16/09
to

OK. We seem to be in agreement that the "lack of a sequence point"
in "break;" or "continue;" is a concept which lacks any meaning
except in the context of a literary review of The C Standard(tm).

Out of curiosity, would you also concede that it is difficult or
impossible to imagine a C compiler(Note 1) which handles
if (setjmp((a, b), c))
properly but mishandles
if (a, setjmp(b, c))

(Note 1: Obviously we exclude compilers which go out of their way
to deliberately mishandle the latter in the spirit of the villain
in the Nicholas Cage movie _8MM_, "just because they could.")

FWIW, James never had a reputation for lackadaisical or imprecise
thinking. I've been consulted by experts to explain the detailed
operations of certain machines. For some reason the mechanisms
whereby 1-bits change to 0-bits in real hardware has intrigued me
in a way that studying whether The Standard(tm) has inconsistencies
in its discussions of commas and semi-colons does not.

Recently I was corrected for suggesting that
p += 0;
might be a no-operation when p is a null pointer.
I immediately thought "Aha!"; perhaps some machines with
1's-complement arithmetic use negative-zero as the null-pointer
representation; adding zero to it flips it to positive-zero
and no longer null -- that's probably why.

Yet, although 2 or 3 people spoke up to clarify The Standard(tm),
no one thought c.l.c'ers had the intellectual curiosity
to wonder *why* (p += 0) might not work on some machines.

I'm retired now, but *loved* C when I was an active programmer.
If I were starting out today, I might have to look elsewhere
for a programming language whose culture suits my temperament.

James Dow Allen

Seebs

unread,
Nov 16, 2009, 12:17:06 AM11/16/09
to
On 2009-11-16, James Dow Allen <jdall...@yahoo.com> wrote:
> Yet, although 2 or 3 people spoke up to clarify The Standard(tm),
> no one thought c.l.c'ers had the intellectual curiosity
> to wonder *why* (p += 0) might not work on some machines.

I'm not that curious, but there's a lot of possible explanations.

e.g., one could imagine a system where emitting code for an address
arithmetic operation does additional checks of the pointer's validity
which aren't otherwise performed.

Kenneth Brody

unread,
Nov 16, 2009, 1:49:58 PM11/16/09
to

Given the definition:

static /* volatile */ int i;

would you say that this does, or does not, include a sequence point?

i;

If not, why not, given that "i++;" definitely does include a sequence point?

And if so, how is "i;" different from "break;" in the context of sequence
points?

--
Kenneth Brody

Keith Thompson

unread,
Nov 16, 2009, 2:25:46 PM11/16/09
to
Kenneth Brody <kenb...@spamcop.net> writes:
> Ben Bacarisse wrote:
>> James Dow Allen <jdall...@yahoo.com> writes:
>>
>>> On Nov 15, 1:36 pm, "nits...@gmail.com" <nits...@gmail.com> wrote:
>>>> [snip] ; [snip]
>>> Semi-colon. Less well known, perhaps, than the Comma "sequence point"
>>> but it also serializes.
>>
>> ; does not mean there is a sequence point. For example, there is no
>> sequence point in
>>
>> break;
>>
>> nor in
>>
>> continue;
>>
>> <snip>
>
> Given the definition:
>
> static /* volatile */ int i;
>
> would you say that this does, or does not, include a sequence point?
>
> i;

Yes. See C99 6.8p4. ``i'' is a "full expression"; the end of a full
expression is a sequence point.

> If not, why not, given that "i++;" definitely does include a sequence point?

Mu.

> And if so, how is "i;" different from "break;" in the context of
> sequence points?

The difference is that ``break'' is not a full expression (or any kind
of expression).

Luca Forlizzi

unread,
Nov 17, 2009, 11:05:46 AM11/17/09
to
On 15 Nov, 18:33, Seebs <usenet-nos...@seebs.net> wrote:

> On 2009-11-15, nits...@gmail.com <nits...@gmail.com> wrote:
>
> > Seems like an unanimous vote for "defined". But what if I tell you the
> > argument for "undefined" is this: at line "*l = func_2();", both RHS
> > and the whole assignment expression write to "g", and there is only
> > one sequence point, which is after ";". According to C99, it is
> > undefined to have more than one write to the same variable between one
> > sequence point and the next sequence point.
> > How would you argue against this?
>
> There is another sequence point.  Look at func_2().  Notice that it has
> a statement.  The end of that statement is a sequence point.  That sequence
> point must be hit before the function returns its value.  So, before func_2()
> returns 3, there has been a sequence point after the modification of g.

Some time ago I discovered the thread "i=i++ (almost)" where, I
believe,
Lawrence Kirby has a different opinion.
In the thread, several examples similar to the one posted here have
been discussed, and Mr. Kirby advocates that they shoud be considered
undefined.
Some examples are:
i=f(i++);
i = (i = 2, 3);
i=0*g(); // g is a function that modifies i

The core of its argument, as far as I understand it, is that the
standard does not say that storing the value of an assignment in the
RHS has to occurr after the LHS has been evaluates.

The thread is from 1994: has there been some DR clarifying such
examples
or the debate is still open? :-)

Luca Forlizzi

Flash Gordon

unread,
Nov 17, 2009, 3:59:22 PM11/17/09
to
Luca Forlizzi wrote:
> On 15 Nov, 18:33, Seebs <usenet-nos...@seebs.net> wrote:
>> On 2009-11-15, nits...@gmail.com <nits...@gmail.com> wrote:
>>
>>> Seems like an unanimous vote for "defined". But what if I tell you the
>>> argument for "undefined" is this: at line "*l = func_2();", both RHS
>>> and the whole assignment expression write to "g", and there is only
>>> one sequence point, which is after ";". According to C99, it is
>>> undefined to have more than one write to the same variable between one
>>> sequence point and the next sequence point.
>>> How would you argue against this?
>> There is another sequence point. Look at func_2(). Notice that it has
>> a statement. The end of that statement is a sequence point. That sequence
>> point must be hit before the function returns its value. So, before func_2()
>> returns 3, there has been a sequence point after the modification of g.
>
> Some time ago I discovered the thread "i=i++ (almost)" where, I
> believe,
> Lawrence Kirby has a different opinion.
> In the thread, several examples similar to the one posted here have
> been discussed, and Mr. Kirby advocates that they shoud be considered
> undefined.
> Some examples are:
> i=f(i++);
> i = (i = 2, 3);

The above two are definitely undefined IMHO.

> i=0*g(); // g is a function that modifies i

The above probably is because the multiply by 0 means the value to be
assigned to i can be known prior to calling g.

> The core of its argument, as far as I understand it, is that the
> standard does not say that storing the value of an assignment in the
> RHS has to occurr after the LHS has been evaluates.
>
> The thread is from 1994: has there been some DR clarifying such
> examples
> or the debate is still open? :-)

Well, the example that started this thread was different, and as I
posted earlier I believe it does not invoke undefined behaviour. The
difference being the need to call the function in order to determine the
value to be assigned.
--
Flash Gordon

Flash Gordon

unread,
Nov 17, 2009, 3:57:35 PM11/17/09
to
Luca Forlizzi wrote:
> On 15 Nov, 18:33, Seebs <usenet-nos...@seebs.net> wrote:
>> On 2009-11-15, nits...@gmail.com <nits...@gmail.com> wrote:
>>
>>> Seems like an unanimous vote for "defined". But what if I tell you the
>>> argument for "undefined" is this: at line "*l = func_2();", both RHS
>>> and the whole assignment expression write to "g", and there is only
>>> one sequence point, which is after ";". According to C99, it is
>>> undefined to have more than one write to the same variable between one
>>> sequence point and the next sequence point.
>>> How would you argue against this?
>> There is another sequence point. Look at func_2(). Notice that it has
>> a statement. The end of that statement is a sequence point. That sequence
>> point must be hit before the function returns its value. So, before func_2()
>> returns 3, there has been a sequence point after the modification of g.
>
> Some time ago I discovered the thread "i=i++ (almost)" where, I
> believe,
> Lawrence Kirby has a different opinion.
> In the thread, several examples similar to the one posted here have
> been discussed, and Mr. Kirby advocates that they shoud be considered
> undefined.
> Some examples are:
> i=f(i++);
> i = (i = 2, 3);

The above two are definitely undefined IMHO.

> i=0*g(); // g is a function that modifies i

The above probably is because the multiply by 0 means the value to be

assigned to i can be known prior to calling g.

> The core of its argument, as far as I understand it, is that the


> standard does not say that storing the value of an assignment in the
> RHS has to occurr after the LHS has been evaluates.
>
> The thread is from 1994: has there been some DR clarifying such
> examples
> or the debate is still open? :-)

Well, the example that started this thread was different, and as I

David Resnick

unread,
Nov 17, 2009, 5:16:38 PM11/17/09
to
On Nov 15, 5:01 am, Flash Gordon <s...@spam.causeway.com> wrote:
> Nick wrote:

Hmmm. How is that different than the program below, which I was
assured was UB some time ago (and which broken when we changed a gcc
version)?

#include <stdio.h>
#include <stdlib.h>

typedef struct blah
{
int a;
int b;
} blah;

static blah *quux;

static int foo(void)
{
// yes, I know, not safe if it fails, this is a short POC
quux = realloc(quux, 2 * sizeof *quux);
return 2;
}

int main(void)
{
quux = malloc(sizeof *quux);
quux->b = 1;
quux->a = foo();

printf("%d %d\n", quux->a, quux->b);

return 0;
}

Plenty of sequence points there, but this seems bogus. And valgrind
reports it as erroneous too...

-David

pete

unread,
Nov 17, 2009, 5:26:52 PM11/17/09
to

This part of the standard is highly counterintuitive:

N869
6.5.16 Assignment operators

[#4] The order of evaluation of the operands is unspecified.

--
pete

Keith Thompson

unread,
Nov 17, 2009, 5:28:42 PM11/17/09
to
David Resnick <lndre...@gmail.com> writes:
> On Nov 15, 5:01 am, Flash Gordon <s...@spam.causeway.com> wrote:
[...]

>> I believe you are correct that it is completely defined. My reasoning is
>> as follows...
>>
>> There is a sequence point between the assignment in the function and the
>> return statement. There is also a sequence point on returning from the
>> function. Therefore there are sequence points between the assignment
>> inside the function and the assignment outside the function. Simplyfiy
>> the code to the following and it is still well defined...
>>
>> #include <stdio.h>
>> int g = 1;
>>
>> int func_2()
>> {
>>     g = 2; /* Sequence point here */
>>     return 3; /* Sequence point here */
>>
>> }
>>
>> int main()
>> {
>>     g = func_2();
>>     printf("g = %d\n", g);
>>     return 0;}
>>
>
> Hmmm. How is that different than the program below, which I was
> assured was UB some time ago (and which broken when we changed a gcc
> version)?
>
> #include <stdio.h>
> #include <stdlib.h>
>
> typedef struct blah
> {
> int a;
> int b;
> } blah;
>
> static blah *quux;
>
> static int foo(void)
> {
> // yes, I know, not safe if it fails, this is a short POC
> quux = realloc(quux, 2 * sizeof *quux);
> return 2;
> }
>
> int main(void)
> {
> quux = malloc(sizeof *quux);
> quux->b = 1;
> quux->a = foo();
>
> printf("%d %d\n", quux->a, quux->b);
>
> return 0;
> }
>
> Plenty of sequence points there, but this seems bogus. And valgrind
> reports it as erroneous too...

I think the difference is that, in the "quux" example, the evaluation
of the RHS ("foo()") can affect the evaluation of the LHS ("quux->a").
So the following actions:
(1) Evaluate quux->a as an lvalue, determining what object is to
be modified.
(2) Evaluate the RHS, foo() (which also modified quux).
(3) Copy the result of (2) to the object identified by (1).
can occur any either of two orders: (1)(2)(3) or (2)(1)(3).

In the other example, the assignment in question is "g = func_2()".
func_2() modifies the value of g, but it doesn't affect the evaluation
of the LHS of the assignment. (Evaluation the LHS of an assignment
determines the identity of the object to be modified; it doesn't
examine the previous value of the object.)

Note that the C201X draft (the latest is
<http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1401.pdf>) has
substantially modified the way sequence points are described. I find
the new description clearer. I haven't really studied it in any
depth, but it might make these questions easier to resolve.

Keith Thompson

unread,
Nov 17, 2009, 5:37:23 PM11/17/09
to
pete <pfi...@mindspring.com> writes:
[...]

> This part of the standard is highly counterintuitive:
>
> N869
> 6.5.16 Assignment operators
>
> [#4] The order of evaluation of the operands is unspecified.

How is that counterintuitive?

To perform an assignment, you need to (1) evaluate the LHS as an
lvalue, determining the object to be modified, (2) evaluate the RHS,
determining the value to be assigned, and (3) perform the assignment,
modifying the object. Given that the order of evaluation of most
other C operators is unspecified, are you saying you'd intuitively
expect steps (1) and (2) to be performed in some language-specified
order?

In most cases, it doesn't make any difference. Cases where it matters
should probably be rewritten anyway. This:

arr[i=2] = (i=3);

is IMHO bad code, even in a language that defines the order of
evaluation.

pete

unread,
Nov 17, 2009, 6:06:01 PM11/17/09
to
Keith Thompson wrote:
> pete <pfi...@mindspring.com> writes:
> [...]
>
>>This part of the standard is highly counterintuitive:
>>
>>N869
>> 6.5.16 Assignment operators
>>
>> [#4] The order of evaluation of the operands is unspecified.
>
>
> How is that counterintuitive?
>
> To perform an assignment, you need to (1) evaluate the LHS as an
> lvalue, determining the object to be modified, (2) evaluate the RHS,
> determining the value to be assigned, and (3) perform the assignment,
> modifying the object. Given that the order of evaluation of most
> other C operators is unspecified, are you saying you'd intuitively
> expect steps (1) and (2) to be performed in some language-specified
> order?

Yes. I would expect the right operand of the assignment operator
to be evaluated prior to the left operand.

> In most cases, it doesn't make any difference. Cases where it matters
> should probably be rewritten anyway. This:
>
> arr[i=2] = (i=3);
>
> is IMHO bad code, even in a language that defines the order of
> evaluation.

--
pete

Nick

unread,
Nov 18, 2009, 2:09:41 AM11/18/09
to
Flash Gordon <sm...@spam.causeway.com> writes:

> Luca Forlizzi wrote:
>
>> i=0*g(); // g is a function that modifies i
>

> The above probably is [undefined behaviour] because the multiply by 0


> means the value to be assigned to i can be known prior to calling g.

In which case, i=x*g(); // g is a function that modifies i

is "possibly" undefined behaviour, but unless your code is such (and
your compiler is clever enough to notice) that there are known times
when x is zero it won't be (cue endless discussion about whether UB is
absolute or not), because without this knowledge the optimisation can't
take place, and without the optimisation the behaviour is completely
defined.

"Mr Schrodinger, your cat's exhibiting undefined behaviour again".
--
Online waterways route planner: http://canalplan.org.uk
development version: http://canalplan.eu

Phil Carmody

unread,
Nov 18, 2009, 4:33:24 AM11/18/09
to

One learns something new every day. There's probably one just *before*
the space before the break or the continue, but not necessarily.

labelbar:
goto labelfoo;
labelfoo:
goto labelbar;

Seems to have no sequence points at all!

Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1

Phil Carmody

unread,
Nov 18, 2009, 4:44:36 AM11/18/09
to
Seebs <usenet...@seebs.net> writes:
> On 2009-11-15, Keith Thompson <ks...@mib.org> wrote:
>> I still think it's not equivalent,
>> because it can affect the legality of other code in the same
>> translation unit.
>
> Hmmmm.
>
> foo_s.h:
> struct foo { int x; };
>
> foo_f.h:
> int use_foo(struct foo *a);
>
> bar.c:
> #include "foo_s.h"
> #include "foo_f.h"
>
> int main(void) {
> struct foo x = { 0 };
> use_foo(&x);
> }
>
> foo.c:
> #include "foo_s.h"
> struct bar { int x; };
> extern int use_foo(struct bar *b) {
> return b.x;
> }
>
> Common initial sequence says this should work, I think.

No it does not. I think I told you this a couple of weeks ago
where you attempted to use the same logic, and you didn't reply.
You're making up your own language rules, you're not talking
about C.

In ALL-CAPS this time:

STANDALONE STRUCTS HAVE NO 'COMMON INITIAL SEQUENCE' RULE.

Only when they are in a *union* is there such a rider.

Charlton Wilbur

unread,
Nov 18, 2009, 8:52:55 AM11/18/09
to
>>>>> "FG" == Flash Gordon <sm...@spam.causeway.com> writes:

FG> Luca Forlizzi wrote:

>> i=0*g(); // g is a function that modifies i

FG> The above probably is because the multiply by 0 means the value
FG> to be assigned to i can be known prior to calling g.

It's defined because there is a sequence point in the function, at the
semicolon following the statement which modifies i, before the result of
the function is assigned to i.

The following fragment of code has no undefined behavior in it:

int i;

int g()
{
i = i + 1;
return 4;
}

i = g();

The practical ordering:

* The i = g() statement begins to be evaluated.
* g() is evaluated.
* The i = i + 1 statement begins to be evaluated.
* The value of i is read.
* 1 is added to that value.
* That value is stored in i.
* There is a sequence point at the end of the statement
* 4 is returned.
* There is a sequence point at the end of the statement.
* The value 4 is stored in i.

The constraint is thus:

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.

This code meets that criterion and is thus not undefined, at least for
that reason.

Charlton

--
Charlton Wilbur
cwi...@chromatico.net

Keith Thompson

unread,
Nov 18, 2009, 11:02:05 AM11/18/09
to
Phil Carmody <thefatphi...@yahoo.co.uk> writes:
[...]

> STANDALONE STRUCTS HAVE NO 'COMMON INITIAL SEQUENCE' RULE.
>
> Only when they are in a *union* is there such a rider.

True. But I challenge you to to describe a hypothetical
non-contrived conforming C implementation in which common initial
sequences for structs work *only* when they're in a union.

Seebs

unread,
Nov 18, 2009, 2:19:01 PM11/18/09
to
On 2009-11-18, Phil Carmody <thefatphi...@yahoo.co.uk> wrote:
> No it does not. I think I told you this a couple of weeks ago
> where you attempted to use the same logic, and you didn't reply.

Oh, I missed that.

> You're making up your own language rules, you're not talking
> about C.

Possible, but a little surprising to me.

> STANDALONE STRUCTS HAVE NO 'COMMON INITIAL SEQUENCE' RULE.

> Only when they are in a *union* is there such a rider.

And since they could be in a union in a new translation unit, it
has to apply anyway. Build your two structures, build all your code
referring to them. Compile it. Now go build a new module in which
you write
union u {
struct foo f;
struct bar b;
};

Suddenly, they have to have common initial sequences share the same
layout. Since this now has to apply to the already-compiled code, it
must have applied all along.

But in particular, for this SPECIFIC case I'm covered anyway, because even
if we imagine that the padding could vary between two structures, a pointer
to a structure, suitably converted, points to its first member, and vice
versa, so the type punning has to work for the first member. I do not think
it is possible to make a conforming implementation where that won't hold.

Luca Forlizzi

unread,
Nov 19, 2009, 4:17:55 AM11/19/09
to

that's exactly the reason given in that thread

Luca Forlizzi

unread,
Nov 19, 2009, 4:51:54 AM11/19/09
to
On 18 Nov, 14:52, Charlton Wilbur <cwil...@chromatico.net> wrote:

I would have agreed on this reasoning before reading the thread I was
referring to (http://groups.google.it/group/comp.lang.c++/
browse_thread/thread/1de1d00083e2ed67/8644012c80f949da?q=almost+group
%3Acomp.std.c&lnk=nl&)
However now I believe this does not use correctly the concept of
sequence point. Mr. Kirby advocates that sequence points points only
constrain the (direct) operands of the operators that define them. Let
me cite Mr. kirby, discussing the i=0*g(); example:

> "The side effect of updating the stored value of the left operand shall occur
>between the previous and next sequence point"
>clearly permits the 2nd ordering since the only difference is when the
>side effect of the assignment happens. It is constrained by the sequence
>points at the end of the expression and the end of the previous expression
>but it is not constrained by the sequence point defined by the function call
>(because it is no part of the function call). This last part is perhaps
>what needs to be expanded so consider:
> i + (0, i++, 1)
>Clearly in this example the 2 i's are not separated by sequence points
>(the expression is undefined because it depends on whether i or i++ is
>evaluated first). Sequence points only constrain the arguments to the
>operators that define them.

So in your example, according to this view, sequence points before or
inside the function call
does not constrain the order of evaluation of the assignment's
operands. Given that the standard does not say that the side effect of
updating the RHS of the assignment has to occur after the LHS
evaluation (as strange as it can be), in i=g(); there are two writes
to i and no sequence points (related to the assignment) between them.
So I think that your example is undefined, even though I expect that
every implementation produce the same result on it.

However, Mr. Kirby wrote in 1994. It may be that there has been some
official statement from the Committee clarifying the issue.
Does anyone know?

Luca

Luca Forlizzi

unread,
Nov 19, 2009, 5:31:17 AM11/19/09
to
On 19 Nov, 10:51, Luca Forlizzi <luca.forli...@gmail.com> wrote:
>
> So in your example, according to this view, sequence points before or
> inside the function call
> does not constrain the order of evaluation of the assignment's
> operands. Given that the standard does not say that the side effect of
> updating the RHS of the assignment has to occur after the LHS
> evaluation (as strange as it can be), in i=g(); there are two writes
> to i and no sequence points (related to the assignment) between them.
> So I think that your example is undefined, even though I expect that
> every implementation produce the same result on it.
>
> However, Mr. Kirby wrote in 1994. It may be that there has been some
> official statement from the Committee clarifying the issue.
> Does anyone know?
>
> Luca

I answer to myself :) Just after posting the previous message, I gave
a look at the draft N1401.
I found that the description of the assignment operator has changed,
and now there is:
"The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands.
The evaluations of
the operands are unsequenced. "

This is exactly what is needed to render expressions of the form
i=g(); // g modifies i
well defined, since now it's stated that the update of the RHS happens
after the evaluation of the RHS.
So this confirms that Mr. Kirby interpretation of C89/C99 was sound,
requiring a change to make (or at least to clearly make)
such expressions well defined.
The famous i=i++; , though, is still undefined in the new draft.

Luca

pete

unread,
Nov 19, 2009, 6:38:08 AM11/19/09
to

I disagree.
(value computations) != (evaluations)
Side effects are part of evaluations.

I think the main point of


"The evaluations of the operands are unsequenced"

is to say the side effects of the evaluation of the right operand,
may occur after the assignment to the left operand.

--
pete

Charlton Wilbur

unread,
Nov 19, 2009, 9:29:44 AM11/19/09
to
>>>>> "N" == Nick <3-no...@temporary-address.org.uk> writes:

N> In which case, i=x*g(); // g is a function that modifies i

N> is "possibly" undefined behaviour,

Only if g() itself has undefined behavior.

The critical step you're missing is that g() must have at least two
sequence points within it -- one after all the arguments have been
evaluated, just before the function body is entered, and one after the
statement in which i is modified. Regardless of the order in which the
terms of that statement are evaluated, those two sequence points are
enough to prevent it from being undefined behavior.

Now, if g() has something idiotic like i = i++ * i++; in it, sure,
i = x * g(); will result in undefined behavior -- but that's because of the
content of g(), not becauseof the statement i = x * g();

See http://c-faq.com/expr/seqpoints.html.

Richard

unread,
Nov 19, 2009, 9:42:17 AM11/19/09
to
Nick <3-no...@temporary-address.org.uk> writes:

> Flash Gordon <sm...@spam.causeway.com> writes:
>
>> Luca Forlizzi wrote:
>>
>>> i=0*g(); // g is a function that modifies i
>>
>> The above probably is [undefined behaviour] because the multiply by 0
>> means the value to be assigned to i can be known prior to calling g.
>
> In which case, i=x*g(); // g is a function that modifies i
>
> is "possibly" undefined behaviour, but unless your code is such (and

It can only undefined behaviour if g() is undefined.

> your compiler is clever enough to notice) that there are known times
> when x is zero it won't be (cue endless discussion about whether UB is
> absolute or not), because without this knowledge the optimisation can't
> take place, and without the optimisation the behaviour is completely
> defined.

Sounds like nonsense to me. x being is totally defined. Answer is 0 or
crash if g() crashes ...

g() modifying "i" legally would have no affect on the return of g()
being assigned to i.

>
> "Mr Schrodinger, your cat's exhibiting undefined behaviour again".

This is nothing like that.

--
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

Nick

unread,
Nov 19, 2009, 12:24:53 PM11/19/09
to
Charlton Wilbur <cwi...@chromatico.net> writes:

>>>>>> "N" == Nick <3-no...@temporary-address.org.uk> writes:
>
> N> In which case, i=x*g(); // g is a function that modifies i
>
> N> is "possibly" undefined behaviour,
>
> Only if g() itself has undefined behavior.
>
> The critical step you're missing is that g() must have at least two
> sequence points within it -- one after all the arguments have been
> evaluated, just before the function body is entered, and one after the
> statement in which i is modified. Regardless of the order in which the
> terms of that statement are evaluated, those two sequence points are
> enough to prevent it from being undefined behavior.
>
> Now, if g() has something idiotic like i = i++ * i++; in it, sure,
> i = x * g(); will result in undefined behavior -- but that's because of the
> content of g(), not becauseof the statement i = x * g();

I understood the post previous to mine in the thread to say that if x in
the above was a constant zero, then even if g would normally be defined
(although it modifies i) then it wouldn't be, because the multiplication
zero allows the result of x to be discarded, and so for the assignment of
0 to i and the alteration in g to happen "out of order".

So my point was that if the optimiser can see that x will always be zero
by this point, then it can make the optimisation, and then we will get
undefined behaviour. If it can't work that out (even if it would be
true) then it wouldn't.

Phil Carmody

unread,
Nov 19, 2009, 2:27:45 PM11/19/09
to
Keith Thompson <ks...@mib.org> writes:
> Phil Carmody <thefatphi...@yahoo.co.uk> writes:
> [...]
>> STANDALONE STRUCTS HAVE NO 'COMMON INITIAL SEQUENCE' RULE.
>>
>> Only when they are in a *union* is there such a rider.
>
> True. But I challenge you to to describe a hypothetical
> non-contrived conforming C implementation in which common initial
> sequences for structs work *only* when they're in a union.

Challenges, not being explicitly defined by the C standard,
yield undefined behaviour. Consider yourself lucky - you won
a shrug.

Anand Hariharan

unread,
Nov 19, 2009, 3:41:49 PM11/19/09
to
On Nov 17, 2:59 pm, Flash Gordon <s...@spam.causeway.com> wrote:
> Luca Forlizzi wrote:
(...)

>
> > Some time ago I discovered the thread "i=i++ (almost)" where, I
> > believe,
> >  Lawrence Kirby has a different opinion.
> > In the thread, several examples similar to the one posted here have
> > been discussed, and Mr. Kirby advocates that they shoud be considered
> > undefined.
> > Some examples are:
> > i=f(i++);
> > i = (i = 2, 3);
>
> The above two are definitely undefined IMHO.
>

Why is the second example undefined? Doesn't the comma operator
introduce a sequence point?


> > i=0*g(); // g is a function that modifies i
>
> The above probably is because the multiply by 0 means the value to be
> assigned to i can be known prior to calling g.
>

I disagree. What if g() returns NaN? The compiler cannot
(shouldn't?) assume the result of this expression as a given before
calling g().


> > The core of its argument, as far as I understand it, is that the
> > standard does not say that storing the value of an assignment in the
> > RHS has to occurr after the LHS has been evaluates.
>

And I personally think that is just reprehensible. I write this after
looking at Pete and Keith Thompson's follow-ups in the parallel sub-
thread, and I agree with Pete.

C should allow for some UB (like squishing a value into a particular
address), but this is one source of UB that is pernicious and serves
no useful purpose.

- Anand

Charlton Wilbur

unread,
Nov 19, 2009, 4:16:39 PM11/19/09
to
>>>>> "N" == Nick <3-no...@temporary-address.org.uk> writes:

(referring to i = x * g(); )

N> I understood the post previous to mine in the thread to say that
N> if x in the above was a constant zero, then even if g would
N> normally be defined (although it modifies i) then it wouldn't be,
N> because the multiplication zero allows the result of x to be
N> discarded, and so for the assignment of 0 to i and the alteration
N> in g to happen "out of order".

No, because the sequence point at the semicolon following the statement
in g() which modifies i means that all side effects have taken place at
that point. The side effect of modifying i can't hang around through
multiple sequence points before being resolved, which is what your
theory requires.

N> So my point was that if the optimiser can see that x will always
N> be zero by this point, then it can make the optimisation, and
N> then we will get undefined behaviour.

Er, no. The C standard does not allow for short-circuit evaluation of
operands aside from those to && and ||. Now, the "as if" rule means
that the optimizer is allowed to do whatever it likes to the code so
long as the actual result is the same as it would be if there were no
optimization.

So even if you wrote i = 0 * g(); explicitly, the translated code would
have to evaluate g() and handle its side effects.

Charlton Wilbur

unread,
Nov 19, 2009, 4:31:39 PM11/19/09
to
>>>>> "LF" == Luca Forlizzi <luca.f...@gmail.com> writes:

LF> However, Mr. Kirby wrote in 1994. It may be that there has been
LF> some official statement from the Committee clarifying the issue.
LF> Does anyone know?

More relevantly, Mr Kirby was writing about C++.

lawrenc...@siemens.com

unread,
Nov 20, 2009, 1:18:42 PM11/20/09
to
Luca Forlizzi <luca.f...@gmail.com> wrote:
>
> So this confirms that Mr. Kirby interpretation of C89/C99 was sound,
> requiring a change to make (or at least to clearly make)
> such expressions well defined.

That's an unwarranted conclusion. The changes were simply to support
multiple threads; they were not intended to change the required behavior
for a single thread.
--
Larry Jones

I can feel my brain beginning to atrophy already. -- Calvin

Nick Keighley

unread,
Nov 25, 2009, 6:38:19 AM11/25/09
to
On 15 Nov, 20:23, "Malcolm McLean" <regniz...@btinternet.com> wrote:
> "Richard Heathfield" <r...@see.sig.invalid> wrote in message

> >(It is not universally agreed, for much the same reason
> > that it is not universally agreed that oxygen is a good thing for
> > humans to breathe. There's *always* somebody who disagrees...)
>
> Oxydative stress.
>
> Then if we all used fluorine instead of oxygen for our redox reactions which
> sustain life, the fluorine would be considerably more efficient, and food
> would go further. So we'd need less farmland and the environment would
> prosper.

As my chemistry teacher told us "you can always spot someone who works
with flourine, because of the missing fingers and so on. Pretty much
everything interesting in fluourine chemistry is either explosive or
corrosive or both"

Richard Heathfield

unread,
Nov 25, 2009, 7:20:18 AM11/25/09
to
In
<622459ae-833e-49ba...@g26g2000yqe.googlegroups.com>,
Nick Keighley wrote:

> On 15 Nov, 20:23, "Malcolm McLean" <regniz...@btinternet.com> wrote:
>> "Richard Heathfield" <r...@see.sig.invalid> wrote in message
>
>> >(It is not universally agreed, for much the same reason
>> > that it is not universally agreed that oxygen is a good thing for
>> > humans to breathe. There's *always* somebody who disagrees...)
>>
>> Oxydative stress.
>>
>> Then if we all used fluorine instead of oxygen for our redox
>> reactions which sustain life, the fluorine would be considerably
>> more efficient, and food would go further. So we'd need less
>> farmland and the environment would prosper.
>
> As my chemistry teacher told us "you can always spot someone who
> works with flourine, because of the missing fingers and so on.

I never knew baking was so dangerous.

> Pretty much everything interesting in fluourine chemistry is either
> explosive or corrosive or both"

Well, I know about the explosive part - Washburn A Mill and all that.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

Nick Keighley

unread,
Nov 25, 2009, 9:00:25 AM11/25/09
to
On 25 Nov, 12:20, Richard Heathfield <r...@see.sig.invalid> wrote:
> In
> <622459ae-833e-49ba-809a-7fa409033...@g26g2000yqe.googlegroups.com>,

>
>
>
>
>
> Nick Keighley wrote:
> > On 15 Nov, 20:23, "Malcolm McLean" <regniz...@btinternet.com> wrote:
> >> "Richard Heathfield" <r...@see.sig.invalid> wrote in message
>
> >> >(It is not universally agreed, for much the same reason
> >> > that it is not universally agreed that oxygen is a good thing for
> >> > humans to breathe. There's *always* somebody who disagrees...)
>
> >> Oxydative stress.
>
> >> Then if we all used fluorine instead of oxygen for our redox
> >> reactions which sustain life, the fluorine would be considerably
> >> more efficient, and food would go further. So we'd need less
> >> farmland and the environment would prosper.
>
> > As my chemistry teacher told us "you can always spot someone who
> > works with flourine, because of the missing fingers and so on.
>
> I never knew baking was so dangerous.
>
> > Pretty much everything interesting in fluourine chemistry is either
> > explosive or corrosive or both"
>
> Well, I know about the explosive part - Washburn A Mill and all that.


:-)

0 new messages