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

Undefined?

2 views
Skip to first unread message

Tak-Shing Chan

unread,
Nov 5, 2002, 1:30:33 PM11/5/02
to
On 5 Nov 2002, Dan Pop wrote:

> It is not clear (to me, at least), whether the standard makes a
> distinction between translation-time undefined behaviour and execution-time
> undefined behaviour.

It is clear (to everyone else) that the standard only cares
about execution-time undefined behaviour. Here is a strictly
conforming program:

int main(void) { return 0 && (1 / 0); }

[Crossposted to comp.std.c. Corrections are welcomed.]

Tak-Shing

Blah

unread,
Nov 5, 2002, 1:40:22 PM11/5/02
to
*** post for FREE via your newsreader at post.newsfeed.com ***

Actually, it was NOT clear to me, which is why I asked in the first
place.


-----= Posted via Newsfeed.Com, Uncensored Usenet News =-----
http://www.newsfeed.com - The #1 Newsgroup Service in the World!
-----== 100,000 Groups! - 19 Servers! - Unlimited Download! =-----

Jun Woong

unread,
Nov 5, 2002, 2:18:30 PM11/5/02
to
"Tak-Shing Chan" <es...@city.ac.uk> wrote in message
news:Pine.GSO.4.21.0211051820230.5385-100000@swindon...

> On 5 Nov 2002, Dan Pop wrote:
>
> > It is not clear (to me, at least), whether the standard makes a
> > distinction between translation-time undefined behaviour and
execution-time
> > undefined behaviour.
>
> It is clear (to everyone else) that the standard only cares
> about execution-time undefined behaviour.

Dan is right. There is no distinction between translation-time UB and
execution-time UB.

> Here is a strictly
> conforming program:
>
> int main(void) { return 0 && (1 / 0); }
>

Yes, this is a s. c. program. IIRC, the Standard requires an
implementation not to fail to translate and to execute a program
unless every possible execution of the program results in undefined
behavior; if every possible execution of a program results in
undefined behavior, then an implementation is allowed to fail to
translate it.

Thanks.


--
Jun, Woong (myco...@hanmail.net)
Dept. of Physics, Univ. of Seoul

Martin Dickopp

unread,
Nov 5, 2002, 2:55:22 PM11/5/02
to
In comp.lang.c Tak-Shing Chan <es...@city.ac.uk> wrote:
> It is clear (to everyone else) that the standard only cares about
> execution-time undefined behaviour.

It is not clear to me. Section 3.4.3 defines undefined behavior in the
following way:

| 1 undefined behavior
| behavior, upon use of a nonportable or erroneous program construct
| or of erroneous data, for which this International Standard
| imposes no requirements
|
| 2 NOTE Possible undefined behavior ranges from ignoring the
| situation completely with unpredictable results, to behaving
| during translation or program execution in a documented manner
| characteristic of the environment (with or without the issuance of
| a diagnostic message), to terminating a translation or execution
| (with the issuance of a diagnostic message).

I understand the phrase "imposes no requirements" to mean that no
requirements are imposed on either the translation or the execution-
time behavior. The note, although not normative, seems to indicate
that this is in fact the intended meaning.

Martin

Martin Dickopp

unread,
Nov 5, 2002, 3:07:41 PM11/5/02
to
In comp.lang.c Jun Woong <myco...@hanmail.net> wrote:
> "Tak-Shing Chan" <es...@city.ac.uk> wrote in message
> news:Pine.GSO.4.21.0211051820230.5385-100000@swindon...
>> It is clear (to everyone else) that the standard only cares
>> about execution-time undefined behaviour.
>
> Dan is right. There is no distinction between translation-time UB and
> execution-time UB.
>
>> Here is a strictly conforming program:
>>
>> int main(void) { return 0 && (1 / 0); }
>
> Yes, this is a s. c. program.

Now I'm completely confused. If you agree that there is no distinction
between translation-time and execution-time undefined behavior, how
can this program be strictly conforming?

> IIRC, the Standard requires an implementation not to fail to
> translate and to execute a program unless every possible execution
> of the program results in undefined behavior; if every possible
> execution of a program results in undefined behavior, then an
> implementation is allowed to fail to translate it.

Which section of the standard says so?

Martin

Tak-Shing Chan

unread,
Nov 5, 2002, 3:31:41 PM11/5/02
to
On Tue, 5 Nov 2002, Martin Dickopp wrote:

> In comp.lang.c Tak-Shing Chan <es...@city.ac.uk> wrote:
>> It is clear (to everyone else) that the standard only cares about
>> execution-time undefined behaviour.
>
> It is not clear to me. Section 3.4.3 defines undefined behavior in the
> following way:
>
> | 1 undefined behavior
> | behavior, upon use of a nonportable or erroneous program construct
> | or of erroneous data, for which this International Standard
> | imposes no requirements

If the program construct or data is not in the execution
path, how can it ever be used?

Tak-Shing

Martin Dickopp

unread,
Nov 5, 2002, 3:54:04 PM11/5/02
to

It is used by the programmer. S/he uses a nonportable or erroneous
construct and feeds it to the compiler.

This section defines the term "undefined behavior"; it does not define
under what circumstances some behavior is undefined. The latter is
defined in 4 (2).

Martin

Tak-Shing Chan

unread,
Nov 5, 2002, 4:18:50 PM11/5/02
to
On Tue, 5 Nov 2002, Martin Dickopp wrote:

> In comp.lang.c Tak-Shing Chan <es...@city.ac.uk> wrote:
>> If the program construct or data is not in the execution path,
>> how can it ever be used?
>
> It is used by the programmer. S/he uses a nonportable or erroneous
> construct and feeds it to the compiler.

I believe that ``used by the programmer'' is outside the
scope of the standard.

Tak-Shing

E. Gibbons

unread,
Nov 5, 2002, 5:19:34 PM11/5/02
to
In article <Pine.GSO.4.21.0211052021500.10697-100000@swindon>,

This, taken in isolation, sounds to me like it refers to "use" in the
sense of using a construct when *writing* a program. I'd expect some
other word or phrasing to be used, like "upon execution", if that's
what was meant.

After all, programs can "use" macros, #define statements, symbolic
constants, FILE pointers, etc., right? But arguably, these things
no longer exist as such, by the time of *execution*.

#include "somefile.h"

void f(int n)
{
if(n)
do_something();
else
do_something_else();
}

int main(void)
{
f(1);
return 0;
return 1; /*NOTREACHED*/
}

The function f() above, as called from main(), clearly seems to "use" the
if statement. But does it "use" the else? It would certainly have a
different meaning if the else were not there! I would say this program
"uses" if and else. Does it "use" an #include directive? Does it "use"
somefile.h? It "uses" a "/*NOTREACHED*/" comment, does it not? But
surely you'll agree that *that* isn't *executed*!

--Ben

--

Tak-Shing Chan

unread,
Nov 5, 2002, 5:44:17 PM11/5/02
to

According to the as-if rule, your program is equivalent to:

#include "somefile.h"
int main(void) { do_something(); return 0; }

So no, I don't think the ``else'' part is used.

Tak-Shing

E. Gibbons

unread,
Nov 5, 2002, 6:02:23 PM11/5/02
to
In article <Pine.GSO.4.21.0211052241270.14654-100000@swindon>,

Perhaps you're right; I went through all that with defining an
additional function, specifically to guard against the notion that
parts of the program might be optimized out of existence (since I
wanted to use a constant in the test). Perhaps a judiciously-placed
"extern" could help? Or how about this:

#include <stdio.h>

int main(void)
{
f(getchar()=='y');


return 0;
return 1; /*NOTREACHED*/
}

(And the rest same as above.)

All my points above still hold for this modified program, and I hope this
lays to rest your "as-if" diversion. Of course, in *my* interpretation,
"as-if" doesn't matter because "use" refers to constructs that are "used"
in the *source code* of the program, prior to compilation, execution, or
any applicability of "as-if". Anyway, please address my points in light
of this new program.

--Ben

--

Tak-Shing Chan

unread,
Nov 5, 2002, 6:39:43 PM11/5/02
to
On 5 Nov 2002, E. Gibbons wrote:

> In article <Pine.GSO.4.21.0211052241270.14654-100000@swindon>,
> Tak-Shing Chan <es...@city.ac.uk> wrote:
>> So no, I don't think the ``else'' part is used.
>
> Perhaps you're right; I went through all that with defining an
> additional function, specifically to guard against the notion that
> parts of the program might be optimized out of existence (since I
> wanted to use a constant in the test). Perhaps a judiciously-placed
> "extern" could help? Or how about this:
>
> #include <stdio.h>
>
> int main(void)
> {
> f(getchar()=='y');
> return 0;
> return 1; /*NOTREACHED*/
> }
>
> (And the rest same as above.)

You now have two distinct execution paths for this program:
one ``uses'' the if part while the other ``uses'' the else part.

> All my points above still hold for this modified program, and I hope this
> lays to rest your "as-if" diversion. Of course, in *my* interpretation,
> "as-if" doesn't matter because "use" refers to constructs that are "used"
> in the *source code* of the program, prior to compilation, execution, or
> any applicability of "as-if". Anyway, please address my points in light
> of this new program.

If this were true, then you should be able to state whether
the following program invokes undefined behavior or not (prior to
compilation or execution):

#include <stdio.h>
int main() { char s[9]; gets(s); puts(s); }

Can you do this?

Tak-Shing

Jun Woong

unread,
Nov 5, 2002, 6:40:21 PM11/5/02
to
"Martin Dickopp" <firefl...@gmx.net> wrote in message
news:aq98ed$h7r$03$1...@news.t-online.com...

> In comp.lang.c Jun Woong <myco...@hanmail.net> wrote:
> > "Tak-Shing Chan" <es...@city.ac.uk> wrote in message
> > news:Pine.GSO.4.21.0211051820230.5385-100000@swindon...
> >> It is clear (to everyone else) that the standard only cares
> >> about execution-time undefined behaviour.
> >
> > Dan is right. There is no distinction between translation-time UB and
> > execution-time UB.
> >
> >> Here is a strictly conforming program:
> >>
> >> int main(void) { return 0 && (1 / 0); }
> >
> > Yes, this is a s. c. program.
>
> Now I'm completely confused. If you agree that there is no distinction
> between translation-time and execution-time undefined behavior, how
> can this program be strictly conforming?

There seems to be misunderstanding. I said there is no distinction
in the sense of that the criterion is when the visible effect of the
undefined behavior can occur.

int main(void)
{
return 1/0;
}

The every possible execution of this program results in undefined
behavior, so the implementation can do anything in anytime including
translation-time and execution-time.

>
> > IIRC, the Standard requires an implementation not to fail to
> > translate and to execute a program unless every possible execution
> > of the program results in undefined behavior; if every possible
> > execution of a program results in undefined behavior, then an
> > implementation is allowed to fail to translate it.
>
> Which section of the standard says so?
>

A DR that's normative. I think we don't need to discuss on this issue
unless the Standard is not defective in this regard.

IIRC,
- If every possible execution of a program results in undefined
behavior, then the program is not s. c.
- The implementation is not allowed to fail translating or to
executing a program just because some of its possible executions
results in undefined behavior.
- If an expression appears in which a constant expression is required
and the evaluation of the expression results in UB, then the program
is not s. c.

Of course, the provisions of the conformance clause and the
requirements of the entire Standard still apply effectively.

#include <stdio.h>

int foo(int a)
{
if (a == 'x') return 1 / 0;
else return 0;
}

int main(void)
{
return foo(getchar());
}

The expression 1 / 0 *can* cause undefined behavior, but the context
in which it appears doesn't require a constant expression. The program
results in undefined behavior when the return value of getchar()
compare equal to 'x'. But it's just some possible execution of the
program.

int func(void);
double func(int a)
{
return 3.14159;
}

int main(void)
{
return 0;
}

Now, this program is not s. c. since it violates the requirements of
the Standard. An implementation can fail to translate this program.

Jun Woong

unread,
Nov 5, 2002, 6:55:44 PM11/5/02
to
"Jun Woong" <myco...@hanmail.net> wrote in message
news:IFYx9.839$5o4....@news.hananet.net...
[...]

>
> A DR that's normative. I think we don't need to discuss on this issue
> unless the Standard is not defective in this regard.
>

Correction:

"unless the Standard is not defective ..." should read as "unless the
Standard is defective"

Sorry.

Christian Bau

unread,
Nov 5, 2002, 7:20:40 PM11/5/02
to
In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,
Tak-Shing Chan <es...@city.ac.uk> wrote:

Try this one:

int main (void)
{
#pragma undefined behaviour
return 0;
}

E. Gibbons

unread,
Nov 5, 2002, 7:07:52 PM11/5/02
to
In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,

Tak-Shing Chan <es...@city.ac.uk> wrote:
>On 5 Nov 2002, E. Gibbons wrote:
>
>> #include <stdio.h>
>>
>> int main(void)
>> {
>> f(getchar()=='y');
>> return 0;
>> return 1; /*NOTREACHED*/
>> }
>>
>> (And the rest same as above.)
>
> You now have two distinct execution paths for this program:
>one ``uses'' the if part while the other ``uses'' the else part.

But the path that "uses" the if part and doesn't "use" the else part,
by your definition of "use", is still affected if the else is removed.

>> All my points above still hold for this modified program, and I hope this
>> lays to rest your "as-if" diversion. Of course, in *my* interpretation,
>> "as-if" doesn't matter because "use" refers to constructs that are "used"
>> in the *source code* of the program, prior to compilation, execution, or
>> any applicability of "as-if". Anyway, please address my points in light
>> of this new program.
>
> If this were true, then you should be able to state whether
>the following program invokes undefined behavior or not (prior to
>compilation or execution):

That doesn't follow at all.

> #include <stdio.h>
> int main() { char s[9]; gets(s); puts(s); }
>
> Can you do this?

No, of course not. That proves nothing.

But I *can* tell you whether it "uses" gets() or not: it does. It's using
it already, as it sits there on the page. I don't have to execute
anything for this *source code program* to "use" the construct known as
gets().

Please address my points.

--Ben

--

Andreas Kähäri

unread,
Nov 5, 2002, 7:28:30 PM11/5/02
to
Submitted by "Christian Bau" to comp.lang.c:
> In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,
[cut]

>
> Try this one:
>
> int main (void)
> {
> #pragma undefined behaviour

I believe that this will invoke implementation-defined
behaviour, not undefined behaviour. I'm not sure what you
wanted to say with this.

> return 0;
> }


--
Andreas Kähäri --==::{ Have a Unix: netbsd.org
--==::{ This post ends with :wq

Douglas A. Gwyn

unread,
Nov 5, 2002, 11:37:11 PM11/5/02
to
Martin Dickopp wrote:
>>> int main(void) { return 0 && (1 / 0); }
> Now I'm completely confused. If you agree that there is no distinction
> between translation-time and execution-time undefined behavior, how
> can this program be strictly conforming?

How could it not be? The division is not evaluated.

Bruce Wheeler

unread,
Nov 6, 2002, 6:21:01 AM11/6/02
to
On Wed, 06 Nov 2002 09:17:52 +0000, Christian Bau
<christ...@freeserve.co.uk> wrote:

>In article <slrnasgo...@otaku.freeshell.org>,


> Andreas Kähäri <a...@freeshell.org.REMOVE> wrote:
>
>> Submitted by "Christian Bau" to comp.lang.c:
>> > In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,
>> [cut]
>> >
>> > Try this one:
>> >
>> > int main (void)
>> > {
>> > #pragma undefined behaviour
>>
>> I believe that this will invoke implementation-defined
>> behaviour, not undefined behaviour. I'm not sure what you
>> wanted to say with this.
>

>Your believe is wrong. Of course this does _NOT_ invoke implementation
>defined behaviour. Nowhere in the C standard will you find that an
>implementation has to define what it will do if the source code contains
>a line
>
> #pragma undefined behaviour
>
>All pragmas apart from the three or four defined in the C99 Standard
>will invoke undefined behaviour. Check your compiler manual. Does it
>define the behaviour for this pragma or not? Didn't think so. What you
>have got here is an example of _undefined behaviour at compile time_.
>

restoring comp.std.c to the list:

According to the standard, it is implementation defined.

6.10.6 Pragma directive
Semantics
1 A preprocessing directive of the form
# pragma pp-tokens opt new-line
where the preprocessing token STDC does not immediately follow pragma in
the directive (prior to any macro replacement)146) causes the
implementation to behave in an implementation-defined manner. The
behavior might cause translation to fail or cause the translator or the
resulting program to behave in a non-conforming manner. Any such
pragma that is not recognized by the implementation is ignored.

Regards,
Bruce Wheeler

Dan Pop

unread,
Nov 6, 2002, 6:31:59 AM11/6/02
to

Not even at translation-time?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan...@ifh.de

Jun Woong

unread,
Nov 6, 2002, 6:46:04 AM11/6/02
to

"Dan Pop" <Dan...@cern.ch> wrote in message
news:aqaujf$318$1...@sunnews.cern.ch...

> In <3DC89C77...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
>
> >Martin Dickopp wrote:
> >>>> int main(void) { return 0 && (1 / 0); }
> >> Now I'm completely confused. If you agree that there is no distinction
> >> between translation-time and execution-time undefined behavior, how
> >> can this program be strictly conforming?
> >
> >How could it not be? The division is not evaluated.
>
> Not even at translation-time?
>

As I understand, yes; the implementation is not free to fail
translating the construct. The expression following the "return"
statement need not to be a constant expression. See my previous
posting in this thread.

pete

unread,
Nov 6, 2002, 6:57:24 AM11/6/02
to

My MSVC++5.0 compiler won't compile my_example.c

Is my compiler broken ?

/* BEGIN my_example.c */

int main(void) {int zero = 0; return zero && (1 / 0); }

/* END my_example.c */

my_example.c(3) : error C2124: divide or mod by zero

--
pete

Jun Woong

unread,
Nov 6, 2002, 7:37:37 AM11/6/02
to
"pete" <pfi...@mindspring.com> wrote in message
news:3DC903...@mindspring.com...

> Jun Woong wrote:
> >
> > "Tak-Shing Chan" <es...@city.ac.uk> wrote in message
> > news:Pine.GSO.4.21.0211051820230.5385-100000@swindon...
> > > On 5 Nov 2002, Dan Pop wrote:
> > >
> > > > It is not clear (to me, at least), whether the standard makes a
> > > > distinction between translation-time undefined behaviour
> > > > and execution-time undefined behaviour.
> > >
> > > It is clear (to everyone else) that the standard only cares
> > > about execution-time undefined behaviour.
> >
> > Dan is right. There is no distinction between translation-time UB and
> > execution-time UB.
> >
> > > Here is a strictly
> > > conforming program:
> > >
> > > int main(void) { return 0 && (1 / 0); }
> > >
> >
> > Yes, this is a s. c. program. IIRC, the Standard requires an
> > implementation not to fail to translate and to execute a program
> > unless every possible execution of the program results in undefined
> > behavior; if every possible execution of a program results in
> > undefined behavior, then an implementation is allowed to fail to
> > translate it.
>
> My MSVC++5.0 compiler won't compile my_example.c
>
> Is my compiler broken ?
>

Yes. My answer is not from my own interpretation; it's from the
Committee. I don't recall the exact document number but you can find
the identical asnwer from a DR.

Why does MSVC have so many non-conforming features? :(

[skip the example and error message]

James Kuyper Jr.

unread,
Nov 6, 2002, 7:43:34 AM11/6/02
to
Dan Pop wrote:
> In <3DC89C77...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
>
>
>>Martin Dickopp wrote:
>>
>>>>> int main(void) { return 0 && (1 / 0); }
>>>>
>>>Now I'm completely confused. If you agree that there is no distinction
>>>between translation-time and execution-time undefined behavior, how
>>>can this program be strictly conforming?
>>
>>How could it not be? The division is not evaluated.
>
>
> Not even at translation-time?

If the compiler pre-evaluates the expression, it must pre-evalute it
correctly, respecting the short-circuiting properties of &&.

In a case where the branch depends upon data processed at run-time, the
compiler must defer the undefined consequences of pre-computing 1/0,
until after it has verified that the branch was taken which actually
results in that computation; if it can't defer those consequences, its
not allowed to pre-compute it.

Martin Dickopp

unread,
Nov 6, 2002, 7:50:57 AM11/6/02
to
In comp.lang.c Jun Woong <myco...@hanmail.net> wrote:
> - The implementation is not allowed to fail translating or to
> executing a program just because some of its possible executions
> results in undefined behavior.

Sorry, but I still don't see how this assumption can be derived from
the words of the standard.

Martin

Jun Woong

unread,
Nov 6, 2002, 8:05:32 AM11/6/02
to

"Martin Dickopp" <firefl...@gmx.net> wrote in message
news:aqb37h$tho$01$1...@news.t-online.com...

The Committee's answer from the DR system has the equivalent force
to the wording of the Standard itself.

Jeremy Yallop

unread,
Nov 6, 2002, 8:29:44 AM11/6/02
to
Bill Godfrey wrote:

> "Jun Woong" <myco...@hanmail.net> wrote:
> > > My MSVC++5.0 compiler won't compile my_example.c
> > > Is my compiler broken ?
>
> > Yes. My answer is not from my own interpretation; it's from the
> > Committee. I don't recall the exact document number but you can find
> > the identical asnwer from a DR.
>
> If reporting the snipped example as an error is broken, then I'll take
> broken over "fixed", thank you very much.

Reporting the error is fine. Refusal to translate the program is not.

Jeremy.

Bill Godfrey

unread,
Nov 6, 2002, 8:20:51 AM11/6/02
to
"Jun Woong" <myco...@hanmail.net> wrote:
> > My MSVC++5.0 compiler won't compile my_example.c
> > Is my compiler broken ?

> Yes. My answer is not from my own interpretation; it's from the
> Committee. I don't recall the exact document number but you can find
> the identical asnwer from a DR.

If reporting the snipped example as an error is broken, then I'll take


broken over "fixed", thank you very much.

Bill, IMHO.

Tak-Shing Chan

unread,
Nov 6, 2002, 8:22:32 AM11/6/02
to
On 6 Nov 2002, E. Gibbons wrote:

> In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,
> Tak-Shing Chan <es...@city.ac.uk> wrote:
>>On 5 Nov 2002, E. Gibbons wrote:
>> You now have two distinct execution paths for this program:
>>one ``uses'' the if part while the other ``uses'' the else part.
>
> But the path that "uses" the if part and doesn't "use" the else part,
> by your definition of "use", is still affected if the else is removed.

You are saying that ``A doesn't use B but is still affected
if B is removed,'' which contradicts the as-if rule.

>> If this were true, then you should be able to state whether
>>the following program invokes undefined behavior or not (prior to
>>compilation or execution):
>
> That doesn't follow at all.

It does follow, because given your definition of ``use'',
you should be able to tell it from source code alone.

>> #include <stdio.h>
>> int main() { char s[9]; gets(s); puts(s); }
>>
>> Can you do this?
>
> No, of course not. That proves nothing.

If you cannot do this, then it is a proof that your
definition of ``use'' is flawed.

> But I *can* tell you whether it "uses" gets() or not: it does. It's using
> it already, as it sits there on the page. I don't have to execute
> anything for this *source code program* to "use" the construct known as
> gets().

Irrelevant. Without knowing the user input in advance, you
cannot even try to tell me whether it ``uses'' s[5] or not.

> Please address my points.

I have already done so.

Tak-Shing

pete

unread,
Nov 6, 2002, 9:12:58 AM11/6/02
to

I don't know why.
Thank you.

--
pete

Martin Dickopp

unread,
Nov 6, 2002, 9:53:41 AM11/6/02
to
In comp.lang.c Jun Woong <myco...@hanmail.net> wrote:
> "Martin Dickopp" <firefl...@gmx.net> wrote in message
> news:aq98ed$h7r$03$1...@news.t-online.com...
>> In comp.lang.c Jun Woong <myco...@hanmail.net> wrote:
>> > IIRC, the Standard requires an implementation not to fail to
>> > translate and to execute a program unless every possible execution
>> > of the program results in undefined behavior; if every possible
>> > execution of a program results in undefined behavior, then an
>> > implementation is allowed to fail to translate it.
>>
>> Which section of the standard says so?
>
> A DR that's normative.

Are you refering to DR#247?

Martin

Jun Woong

unread,
Nov 6, 2002, 10:56:16 AM11/6/02
to

"Martin Dickopp" <firefl...@gmx.net> wrote in message
news:aqbadl$jir$06$1...@news.t-online.com...

No, DR#247 deals with the connection between use of values and
behaviors, which is irrelevant to this problem.

See DR#109 and DR#132.

http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_109.html
http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_132.html

Martin Dickopp

unread,
Nov 6, 2002, 1:20:10 PM11/6/02
to

Thanks!

I have not found these because I misunderstood how the standardization
process works. Since I didn't know that DRs from 1993 are a normative
part of the current (1999) C standard, I didn't even look at these old
DRs. The fact that the WG14 www site has a page entitled "WG14 Defect
Report Summary for ISO/IEC 9899:1999", which does not include these old
reports, made me believe that older DRs are not relevant.

Martin

E. Gibbons

unread,
Nov 6, 2002, 2:12:25 PM11/6/02
to
In article <Pine.GSO.4.21.0211061258370.4297-100000@swindon>,

Tak-Shing Chan <es...@city.ac.uk> wrote:
>On 6 Nov 2002, E. Gibbons wrote:
>
>> In article <Pine.GSO.4.21.0211052332020.16848-100000@swindon>,
>> Tak-Shing Chan <es...@city.ac.uk> wrote:
>>>On 5 Nov 2002, E. Gibbons wrote:
>>> You now have two distinct execution paths for this program:
>>>one ``uses'' the if part while the other ``uses'' the else part.
>>
>> But the path that "uses" the if part and doesn't "use" the else part,
>> by your definition of "use", is still affected if the else is removed.
>
> You are saying that ``A doesn't use B but is still affected
>if B is removed,'' which contradicts the as-if rule.

No, *you* are saying A doesn't use B, and *I* am making the point that it
*must* use B, because if B is removed, the behaviour changes. It's all
plainly quoted above. Try to keep the arguments straight, here!

>>> If this were true, then you should be able to state whether
>>>the following program invokes undefined behavior or not (prior to
>>>compilation or execution):
>>
>> That doesn't follow at all.
>
> It does follow, because given your definition of ``use'',
>you should be able to tell it from source code alone.

But you weren't asking about "use". As I said, quoted below, I *can*
tell whether it "uses" a given construct, by my interpretation of "use".

>>> #include <stdio.h>
>>> int main() { char s[9]; gets(s); puts(s); }
>>>
>>> Can you do this?
>>
>> No, of course not. That proves nothing.
>
> If you cannot do this, then it is a proof that your
>definition of ``use'' is flawed.

No, it is a proof that a program can "use" a construct, according to
my interpretation of "use", without *executing* that construct, which
seems to be what your interpretation of "use" amounts to.

>> But I *can* tell you whether it "uses" gets() or not: it does. It's using
>> it already, as it sits there on the page. I don't have to execute
>> anything for this *source code program* to "use" the construct known as
>> gets().
>
> Irrelevant. Without knowing the user input in advance, you
>cannot even try to tell me whether it ``uses'' s[5] or not.

Yes, I can, and in fact I did tell you so. Please read my quoted text
above carefully.

>> Please address my points.
>
> I have already done so.

No, you haven't. You have demonstrated rather clearly that you don't
understand my point.

Here, let's try some fresh code, with even less ambiguity.

#include <stdio.h>

int main(void)
{
char * p;

if(0) {
gets(p);
}
return 0;
}

By my definition, this program "uses" gets(), although it will never
*execute* it, and thus does not invoke UB. And that's why it needs to
#include <stdio.h>.

By your definition, it does not "use" gets(). Why, then, does it
need to "use" stdio.h?

What if a construct is optimized out? How can you tell whether it is
"used" or not?

What if you compile the program, but never actually run it? Does it
"use" nothing, then? What if you only run it if a radioactive decay
event causes a cat to die in an underground lab somewhere? What if
you run 3000 copies in parallel? Does your program "use" main() 3000
times, then (but only while they're running)?

Your definition amounts to "executes the construct", mine amounts to
"contains the construct". Yours is awkward, and is *fundamentally
undecideable* in the general case; and it loses the distinction between
"contains" and "executes"; and, it falls down completely for constructs
that simply are *not* executable, such as comments, preprocessor
directives, etc.. So, although neither of us knows for certain which
sense the Standard intended in the original quote, I think my sense
of the word makes more sense, is more decideable, and has more value,
in general.

But as they say, YMMV. The real question is what the *Standard* means
by "use", and all we have shown here is that two non-experts disagree.

--Ben

--

James Kuyper

unread,
Nov 6, 2002, 3:27:50 PM11/6/02
to

That's actually a matter which has been hotly debated. For C90 DR
decisions which provide official interpretations of the wording of the
standard, if none of the relevant text changed in C99, than neither did
the interpretation.

However, many DR decisions are based upon text which did change. Those
decisions can't be carried over to C99. For example, the resolution to
DR005 says in part "No, a strictly conforming program may not contain a
pragma directive." With the addition of the new standard pragmas in C99,
this conclusion has to be false.
It can sometimes be difficult to determine precisely which text the
committee based it's decisions on - when that's the case, it's
correspondingly difficult to guess whether or not the decision should
carry over.

Of course, some DR decisions went beyond the actual text of the
standard. The committee had a chance to add supporting text for those
decisions into the new version of the standard; if it failed to do so,
that should be considered as evidence that the C90 decision does not
apply to C99.
However, this is a very controversial area; primarily because there's
disagreement about which DR decisions fall into this category.

Douglas A. Gwyn

unread,
Nov 6, 2002, 10:55:18 PM11/6/02
to
Dan Pop wrote:
> In <3DC89C77...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
>>>>> int main(void) { return 0 && (1 / 0); }
>> The division is not evaluated.
> Not even at translation-time?

No, it must not be.

Dan Pop

unread,
Nov 7, 2002, 5:04:26 AM11/7/02
to

Even if we replace this trivial example by something like:

int main(int argc, char **argv) { return argc && (1 / 0); }

Alexander Terekhov

unread,
Nov 7, 2002, 7:21:15 AM11/7/02
to

Dan Pop wrote:
>
> In <3DC9E426...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
>
> >Dan Pop wrote:
> >> In <3DC89C77...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
> >>>>>> int main(void) { return 0 && (1 / 0); }
> >>> The division is not evaluated.
> >> Not even at translation-time?
> >
> >No, it must not be.
>
> Even if we replace this trivial example by something like:
>
> int main(int argc, char **argv) { return argc && (1 / 0); }

Who's the idiot here, Dan?

regards,
alexander.

James Kuyper Jr.

unread,
Nov 7, 2002, 8:11:37 AM11/7/02
to
Dan Pop wrote:
> In <3DC9E426...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
>
>
>>Dan Pop wrote:
>>
>>>In <3DC89C77...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
...

>>>>The division is not evaluated.
>>>
>>>Not even at translation-time?
>>
>>No, it must not be.
>
>
> Even if we replace this trivial example by something like:
>
> int main(int argc, char **argv) { return argc && (1 / 0); }

An implementation can evaluate the 1/0 at translation time in this case,
only if the implementation can guarantee that argc is non-zero. Since
it's up to the implementation how argc acquires it's non-negative value,
it's quite possible that the implementation can guarantee this.

Tak-Shing Chan

unread,
Nov 7, 2002, 9:16:00 AM11/7/02
to
On 6 Nov 2002, E. Gibbons wrote:

> No, *you* are saying A doesn't use B, and *I* am making the point that it
> *must* use B, because if B is removed, the behaviour changes. It's all

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Wrong. The removal of B does not change the behavior of A:
the behavior of ``if (1) f(); else g();'' is exactly the same as
the behavior of ``if (1) f();''.

> No, it is a proof that a program can "use" a construct,

You have not proved anything yet. What you have done so
far, is to invent a definition of your own, which the standard
disagrees with.

> Yes, I can, and in fact I did tell you so. Please read my quoted text

You did not. Does it ``use'' s[5]? I found no answer in
your previous posts.

> #include <stdio.h>
>
> int main(void)
> {
> char * p;
>
> if(0) {
> gets(p);
> }
> return 0;
> }
>
> By my definition, this program "uses" gets(), although it will never
> *execute* it, and thus does not invoke UB. And that's why it needs to
> #include <stdio.h>.

It does not follow.

> By your definition, it does not "use" gets(). Why, then, does it
> need to "use" stdio.h?

It does not need to. Please read the relevant DRs (see
Jun Woong's posts). According to the DR responses, the following
translation unit *must* be successfully translated:

int checkup()
{
if (0) printf("Printing.\n"); /* Missing prototype */
return 2 || 1 / 0; /* Division by zero */
}

Clearly, printf() is not used here, otherwise it contradicts
with the committee's official response.

Tak-Shing

Tak-Shing Chan

unread,
Nov 7, 2002, 9:23:06 AM11/7/02
to
On Thu, 7 Nov 2002, James Kuyper Jr. wrote:

> Dan Pop wrote:
>> int main(int argc, char **argv) { return argc && (1 / 0); }
>
> An implementation can evaluate the 1/0 at translation time in this case,
> only if the implementation can guarantee that argc is non-zero. Since
> it's up to the implementation how argc acquires it's non-negative value,
> it's quite possible that the implementation can guarantee this.

Since the as-if rule is located under ``program execution'',
I believe that precomputation does not count as evaluation.

Tak-Shing

James Kuyper Jr.

unread,
Nov 7, 2002, 9:45:44 AM11/7/02
to

Under the as-if rule, pre-computation is allowed only if it produces
effects which are indistinguishable from effects which would also be
legal if it performed the evaluation at run-time, instead. It's not
allowed to make the program's translation and execution fail because of
that pre-computation, unless and until it can guarantee that argc is
non-zero. That could be guaranteed at compile time, for some
implementations.

However, consider an implementation that documents a way of invoking the
program which guarantees argc==0. Such an implementation cannot fail to
correctly translate and execute this program, if it is actually invoked
in that fashion (modulo implementation limits issues).

t...@cs.ucr.edu

unread,
Nov 7, 2002, 11:22:40 AM11/7/02
to
In comp.std.c James Kuyper Jr. <kuy...@wizard.net> wrote:
+ Tak-Shing Chan wrote:
+ > On Thu, 7 Nov 2002, James Kuyper Jr. wrote:
+ >
+ >
+ >>Dan Pop wrote:
+ >>
+ >>> int main(int argc, char **argv) { return argc && (1 / 0); }
+ >>
+ >>An implementation can evaluate the 1/0 at translation time in this case,
+ >>only if the implementation can guarantee that argc is non-zero. Since
+ >>it's up to the implementation how argc acquires it's non-negative value,
+ >>it's quite possible that the implementation can guarantee this.
+ >
+ >
+ > Since the as-if rule is located under ``program execution'',
+ > I believe that precomputation does not count as evaluation.
+
+ Under the as-if rule, pre-computation is allowed only if it produces
+ effects which are indistinguishable from effects which would also be
+ legal if it performed the evaluation at run-time, instead. It's not
+ allowed to make the program's translation and execution fail because of
+ that pre-computation, unless and until it can guarantee that argc is
+ non-zero. That could be guaranteed at compile time, for some
+ implementations.
+
+ However, consider an implementation that documents a way of invoking the
+ program which guarantees argc==0. Such an implementation cannot fail to
+ correctly translate and execute this program, if it is actually invoked
+ in that fashion (modulo implementation limits issues).

I agree, but I suspect that fewer will agree if we modify the example
slightly:

int main(int argc, char **argv) { return argc && (*0 = 1); }
^
assignment

Assuming that argc can be zero, must the implementation translate this
program? I.e., is "*0" a legitimate lvalue here?

Tom Payne

Jeremy Yallop

unread,
Nov 7, 2002, 11:56:41 AM11/7/02
to
* t...@cs.ucr.edu

| int main(int argc, char **argv) { return argc && (*0 = 1); }
| ^
| assignment
|
| Assuming that argc can be zero, must the implementation translate this
| program? I.e., is "*0" a legitimate lvalue here?

No, it's a constraint violation. '0' doesn't have pointer type.

Jeremy.

t...@cs.ucr.edu

unread,
Nov 7, 2002, 12:05:56 PM11/7/02
to
In comp.std.c E. Gibbons <euph...@u.washington.edu> wrote: [...] +
All my points above still hold for this modified program, and I hope
this + lays to rest your "as-if" diversion. Of course, in *my*
interpretation, + "as-if" doesn't matter because "use" refers to
constructs that are "used" + in the *source code* of the program,
prior to compilation, execution, or + any applicability of "as-if".

The term "use" in the definition of "undefined behavior" cannot refer
exclusively to static attributes of the program. For two reasons,
there is no way that static analysis can reliably determine whether or
not division-by-zero will occur at run time.

Reason #1: There is no way to predict input:

int n;
n = user_input();
1/n;

Reason #2: Even when there is no external input, determining whether
or not a given variable will ever take on the value zero at a given
point in the program is equivalent to the halting problem, i.e., there
is no algorithm for determining whether or not this situaiton will
occur.

Tom Payne

Douglas A. Gwyn

unread,
Nov 7, 2002, 3:08:01 PM11/7/02
to
Dan Pop wrote:
> Even if we replace this trivial example by something like:
> int main(int argc, char **argv) { return argc && (1 / 0); }

If argc might be zero, then the division must not be evaluated
at translation time (or at any rate the program must be
translated and made ready for execution). If the implementation
is such that argc can never be zero at run time, then the
division may be performed at translation time, and among the
possible allowed behaviors would be failure to produce an
executable image, plus warning about the division by zero.

I don't see what is so hard to understand: execution occurs
at run time, not translation time (except for constant
expressions, which are such only in contexts where they are
required to be such); and if an implementation can determine
with certainty that undefined behavior would occur when the
program is executed, it has the option to not execute it.

Douglas A. Gwyn

unread,
Nov 7, 2002, 3:12:28 PM11/7/02
to
Bill Godfrey wrote:
> If reporting the snipped example as an error is broken,
> then I'll take broken over "fixed", thank you very much.

Why? The program had perfectly reasonable, well-defined
properties, but that compiler refused to accept it. Now,
a *warning* about possible division by zero might be
useful, but not an outright refusal to compile.

E. Gibbons

unread,
Nov 7, 2002, 4:40:41 PM11/7/02
to
In article <Pine.GSO.4.21.0211071323340.15895-100000@swindon>,

Tak-Shing Chan <es...@city.ac.uk> wrote:
>On 6 Nov 2002, E. Gibbons wrote:
>
>> No, *you* are saying A doesn't use B, and *I* am making the point that it
>> *must* use B, because if B is removed, the behaviour changes. It's all
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Wrong. The removal of B does not change the behavior of A:
>the behavior of ``if (1) f(); else g();'' is exactly the same as
>the behavior of ``if (1) f();''.

But it's not the same as "if(1) f(); g();", which was what was under
discussion. "B" is "else". Read the thread.

>> No, it is a proof that a program can "use" a construct,
>
> You have not proved anything yet. What you have done so
>far, is to invent a definition of your own, which the standard
>disagrees with.

You have not shown that the standard disagrees. If you can do so,
do it now.

>> Yes, I can, and in fact I did tell you so. Please read my quoted text
>
> You did not. Does it ``use'' s[5]? I found no answer in
>your previous posts.

I answered that *twice* already.

>> #include <stdio.h>
>>
>> int main(void)
>> {
>> char * p;
>>
>> if(0) {
>> gets(p);
>> }
>> return 0;
>> }
>>
>> By my definition, this program "uses" gets(), although it will never
>> *execute* it, and thus does not invoke UB. And that's why it needs to
>> #include <stdio.h>.
>
> It does not follow.
>
>> By your definition, it does not "use" gets(). Why, then, does it
>> need to "use" stdio.h?
>
> It does not need to. Please read the relevant DRs (see
>Jun Woong's posts). According to the DR responses, the following
>translation unit *must* be successfully translated:
>
> int checkup()
> {
> if (0) printf("Printing.\n"); /* Missing prototype */
> return 2 || 1 / 0; /* Division by zero */
> }
>
> Clearly, printf() is not used here, otherwise it contradicts
>with the committee's official response.

Well, I guess the gcc people haven't read that DR (which DR is it,
please?):

gemini[pts/3]:~/tmp$ cat checkup.c


int checkup()
{
if (0) printf("Printing.\n"); /* Missing prototype */
return 2 || 1 / 0; /* Division by zero */
}

gemini[pts/3]:~/tmp$ gcc -ansi -pedantic -Wall -W -Werror -O2 -c checkup.c -o checkup.o
cc1: warnings being treated as errors
checkup.c: In function `checkup':
checkup.c:3: warning: implicit declaration of function `printf'
gemini[pts/3]:~/tmp$ ls -l checkup.*
-rw-r--r-- 1 bketcham bketcham 157 Nov 7 13:34 checkup.c

--Ben


--

Barry Margolin

unread,
Nov 7, 2002, 5:35:32 PM11/7/02
to
In article <aqemkp$1sjo$1...@nntp6.u.washington.edu>,

E. Gibbons <euph...@u.washington.edu> wrote:
>Well, I guess the gcc people haven't read that DR (which DR is it,
>please?):
>
>gemini[pts/3]:~/tmp$ cat checkup.c
> int checkup()
> {
> if (0) printf("Printing.\n"); /* Missing prototype */
> return 2 || 1 / 0; /* Division by zero */
> }
>gemini[pts/3]:~/tmp$ gcc -ansi -pedantic -Wall -W -Werror -O2 -c
>checkup.c -o checkup.o
>cc1: warnings being treated as errors
>checkup.c: In function `checkup':
>checkup.c:3: warning: implicit declaration of function `printf'
>gemini[pts/3]:~/tmp$ ls -l checkup.*
>-rw-r--r-- 1 bketcham bketcham 157 Nov 7 13:34 checkup.c

It was merely warning about the missing prototype, but you made use of an
option that tells it to treat warning-level situations as errors (it even
told you that it was doing that). Why would you expect standard-conforming
behavior when you've specifically told it to do this?

--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

James Kuyper

unread,
Nov 7, 2002, 5:44:02 PM11/7/02
to
"E. Gibbons" wrote:
>
> In article <Pine.GSO.4.21.0211071323340.15895-100000@swindon>,
> Tak-Shing Chan <es...@city.ac.uk> wrote:
...

> > It does not need to. Please read the relevant DRs (see
> >Jun Woong's posts). According to the DR responses, the following
> >translation unit *must* be successfully translated:
...

> Well, I guess the gcc people haven't read that DR (which DR is it,
> please?):

Check back on the other branch of this thread - the one that doesn't
have you and Tak-Shing arguing back and forth. Jun Woong's message dated
"Thu, 7 Nov 2002 00:56:16 +0900" contains links to the relevant DRs.

> gemini[pts/3]:~/tmp$ cat checkup.c
> int checkup()
> {
> if (0) printf("Printing.\n"); /* Missing prototype */
> return 2 || 1 / 0; /* Division by zero */
> }
> gemini[pts/3]:~/tmp$ gcc -ansi -pedantic -Wall -W -Werror -O2 -c checkup.c -o checkup.o
> cc1: warnings being treated as errors
> checkup.c: In function `checkup':
> checkup.c:3: warning: implicit declaration of function `printf'

You told it to treat warnings as errors; that's not one of the options
you can use if you want to invoke gcc in a fully conforming mode. With
that option turned off, it warns about a great many things, some of
which are perfectly legal; but it goes ahead and compiles the code
anyway, so it is conforming. With that option turned on, it refuses to
compile those same things, including the ones that are perfectly legal,
making it no longer a conforming implementation.

Chris Torek

unread,
Nov 8, 2002, 2:12:35 AM11/8/02
to
In article <aqe6hk$7fa$1...@glue.ucr.edu> <t...@cs.ucr.edu> wrote:
>The term "use" in the definition of "undefined behavior" cannot refer
>exclusively to static attributes of the program. For two reasons,
>there is no way that static analysis can reliably determine whether or
>not division-by-zero will occur at run time.
>
> Reason #1: There is no way to predict input:
>
> int n;
> n = user_input();
> 1/n;
>
> Reason #2: Even when there is no external input, determining whether
> or not a given variable will ever take on the value zero at a given
> point in the program is equivalent to the halting problem, i.e., there
> is no algorithm for determining whether or not this situaiton will
> occur.

These are both valid general-case arguments, i.e., there exist
programs and inputs for which they are true. They are not valid
specific-case arguments, i.e., there may exist other programs (for
case #2) or implementations (for case #1) where the results *can*
be predicted in advance, even as far ahead as compile-time.

(For instance, a program that uses scanf("%d", &n) to read an
integer from stdin might be absolutely guaranteed to get EOF every
time, leaving "n" unchanged, on some implementation. The
compiler implementor simply "knows" that stdin is always connected
to the equivalent of /dev/null, and all attempts to freopen() it
fail, and so on.)

Since the standard has to talk about general cases, this is just
a nit. :-)
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA Domain: to...@bsdi.com
http://67.40.109.61/torek/ (for the moment)
(you probably cannot email me -- spam has effectively killed email)

Dan Pop

unread,
Nov 8, 2002, 4:18:25 AM11/8/02
to

The point is that this conclusion cannot be drawn *exclusively* from the
text of the standard (you also have to read the minds of the committee
members or some DRs filed against an obsolete version of the standard).

The purpose of my questions was to get the issue fully clarified,
for the benefit of everyone following this discussion.

The above-mentioned DRs have provided ample proof that the text of C89
was defective in that area. Yet, the committee decided not to take any
corrective action(s) in C99. Any good reasons for this decision?

Dan Pop

unread,
Nov 8, 2002, 4:43:11 AM11/8/02
to
In <aqemkp$1sjo$1...@nntp6.u.washington.edu> euph...@u.washington.edu (E. Gibbons) writes:

>Well, I guess the gcc people haven't read that DR (which DR is it,
>please?):
>
>gemini[pts/3]:~/tmp$ cat checkup.c
> int checkup()
> {
> if (0) printf("Printing.\n"); /* Missing prototype */
> return 2 || 1 / 0; /* Division by zero */
> }
>gemini[pts/3]:~/tmp$ gcc -ansi -pedantic -Wall -W -Werror -O2 -c checkup.c -o checkup.o
>cc1: warnings being treated as errors
>checkup.c: In function `checkup':
>checkup.c:3: warning: implicit declaration of function `printf'
>gemini[pts/3]:~/tmp$ ls -l checkup.*
>-rw-r--r-- 1 bketcham bketcham 157 Nov 7 13:34 checkup.c

What makes you think that gcc is (or should be) a conforming translator
when using the -Werror option?

The semantics of the -Werror option are: "don't complete the
translation if a diagnostic was produced" and NOT "don't complete
the translation if a *required* diagnostic is produced". And both
-Wall and -W ask gcc to generate even more diagnostics that are NOT
required by the standard.

If you still don't get it, consider the following strictly conforming
program:

fangorn:~/tmp 28> cat test.c
int main()
{
int a = 'ab';
return 0;
}
fangorn:~/tmp 29> gcc -c -Werror test.c


cc1: warnings being treated as errors

test.c: In function `main':
test.c:3: warning: multi-character character constant
fangorn:~/tmp 30> echo $status
1
fangorn:~/tmp 31> ls test.o
ls: test.o: No such file or directory

Remove -Werror and the program is correctly translated.

Clive D. W. Feather

unread,
Nov 8, 2002, 7:37:12 AM11/8/02
to
In article <aqe609$97nja$1...@ID-114079.news.dfncis.de>, Jeremy Yallop
<jer...@jdyallop.freeserve.co.uk> writes

>No, it's a constraint violation. '0' doesn't have pointer type.

But it's a null pointer constant, so can be used as a pointer in at
least some cases.

--
Clive D.W. Feather, writing for himself | Home: <cl...@davros.org>
Tel: +44 20 8371 1138 (work) | Web: <http://www.davros.org>
Fax: +44 870 051 9937 | Work: <cl...@demon.net>
Written on my laptop; please observe the Reply-To address

Clive D. W. Feather

unread,
Nov 8, 2002, 7:37:58 AM11/8/02
to
In article <3DCAC821...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>I don't see what is so hard to understand: execution occurs
>at run time, not translation time (except for constant
>expressions, which are such only in contexts where they are
>required to be such);

Does this mean that WG14 has reached a conclusion on DR 261?

Clive D. W. Feather

unread,
Nov 8, 2002, 7:36:36 AM11/8/02
to
In article <aqbmgq$6d6$00$1...@news.t-online.com>, Martin Dickopp
<firefl...@gmx.net> writes

>Since I didn't know that DRs from 1993 are a normative
>part of the current (1999) C standard,

They aren't.

However, in a number of cases, if the question were asked again WG14
would be likely to give the same response. [Somewhere deep in my ToDo
list is an attempt to document these.]

Jeremy Yallop

unread,
Nov 8, 2002, 8:16:56 AM11/8/02
to
t...@cs.ucr.edu wrote:
>>> int main(int argc, char **argv) { return argc && (*0 = 1); }
>>> ^
>>> assignment
>>>
>>> Assuming that argc can be zero, must the implementation translate this
>>> program? I.e., is "*0" a legitimate lvalue here?

I replied:


>> No, it's a constraint violation. '0' doesn't have pointer type.

Clive D. W. Feather wrote:
> But it's a null pointer constant, so can be used as a pointer in at
> least some cases.

Yes, but not this one. Look at the context (reinstated).

Jeremy.

Francis Glassborow

unread,
Nov 8, 2002, 7:10:41 AM11/8/02
to
In message <3DCAC92C...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes


Not least because (if I understand the rules correctly) division by zero
could result in a NaN and no reason for the program to be aborted.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Richard Bos

unread,
Nov 8, 2002, 8:51:49 AM11/8/02
to
Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:

> t...@cs.ucr.edu wrote:
> >>> int main(int argc, char **argv) { return argc && (*0 = 1); }
> >>> ^
> >>> assignment
> >>>
> >>> Assuming that argc can be zero, must the implementation translate this
> >>> program? I.e., is "*0" a legitimate lvalue here?
>

> >> No, it's a constraint violation. '0' doesn't have pointer type.
>

> > But it's a null pointer constant, so can be used as a pointer in at
> > least some cases.
>
> Yes, but not this one. Look at the context (reinstated).

That's the one-but-inner context. The _actual_ context is the
dereference operator; _it_ requires a pointer context, and thus the 0 is
interpreted as a null pointer constant, which is converted (at compile
time, most likely) to an actual null pointer. This null pointer is then
dereferenced.
As a result, this program is syntactically correct, and invokes
undefined behaviour only when argc != 0. If the compiler can determine
that argc will always be positive (for example, if it knows it will
always be able to supply argv[0]), it is AFAICT allowed not to compile
it; but if the compiler cannot be sure argc will never be 0, it _must_
compile this program.

Richard

t...@cs.ucr.edu

unread,
Nov 8, 2002, 8:37:03 AM11/8/02
to
In comp.std.c Richard Bos <r...@hoekstra-uitgeverij.nl> wrote:
+ Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
+
+> t...@cs.ucr.edu wrote:
+> >>> int main(int argc, char **argv) { return argc && (*0 = 1); }
+> >>> ^
+> >>> assignment
+> >>>
+> >>> Assuming that argc can be zero, must the implementation translate this
+> >>> program? I.e., is "*0" a legitimate lvalue here?
+>
+> >> No, it's a constraint violation. '0' doesn't have pointer type.
+>
+> > But it's a null pointer constant, so can be used as a pointer in at
+> > least some cases.
+>
+> Yes, but not this one. Look at the context (reinstated).
+
+ That's the one-but-inner context. The _actual_ context is the
+ dereference operator; _it_ requires a pointer context, and thus the 0 is
+ interpreted as a null pointer constant, which is converted (at compile
+ time, most likely) to an actual null pointer. This null pointer is then
+ dereferenced.
+ As a result, this program is syntactically correct, and invokes
+ undefined behaviour only when argc != 0. If the compiler can determine
+ that argc will always be positive (for example, if it knows it will
+ always be able to supply argv[0]), it is AFAICT allowed not to compile
+ it; but if the compiler cannot be sure argc will never be 0, it _must_
+ compile this program.

That's exactly how I see it. It follows, however, that "*0" is an
lvalue even though it does not designate an object. Lots of folks
seems to balk at that.

Tom Payne

Joona I Palaste

unread,
Nov 8, 2002, 9:06:28 AM11/8/02
to
t...@cs.ucr.edu scribbled the following
on comp.lang.c:

I do not understand this. How can *0 be a syntactically and
contextually valid expression? The unary * operator means the thing
that is stored at the address given by the operand. Here, it's clear
that the thing is stored at address 0, but no one bothered to tell what
type of thing it is: char, int, long...

--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"It sure is cool having money and chicks."
- Beavis and Butt-head

James Kuyper Jr.

unread,
Nov 8, 2002, 9:39:43 AM11/8/02
to

Richard Bos wrote:
> Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
>
>
>>t...@cs.ucr.edu wrote:
>>
>>>>> int main(int argc, char **argv) { return argc && (*0 = 1); }
>>>>> ^
>>>>> assignment
>>>>>
>>>>>Assuming that argc can be zero, must the implementation translate this
>>>>>program? I.e., is "*0" a legitimate lvalue here?
>>>>
>>>>No, it's a constraint violation. '0' doesn't have pointer type.
>>>
>>>But it's a null pointer constant, so can be used as a pointer in at
>>>least some cases.
>>
>>Yes, but not this one. Look at the context (reinstated).
>
>
> That's the one-but-inner context. The _actual_ context is the
> dereference operator; _it_ requires a pointer context, and thus the 0 is
> interpreted as a null pointer constant, which is converted (at compile
> time, most likely) to an actual null pointer. This null pointer is then
> dereferenced.

Nice theory. Do you have supporting text for this interpretation?

There is no general rule that makes '0' convert to a pointer type just
because one is needed. There's just a few individual rules for
particular cases; and this isn't one of them. Those cases include
6.5.9p2 for == and !=, 6.5.15p3 for ?:, and 6.5.16p2 for the assignment
operators. Each of those paragraphs has a special option to allow for
one of the operands to be a null pointer constant while another operand
is a pointer.

Sections 6.5.9p5 and 6.5.15p3 each contain special wording describing
the kind of conversion you're talking about, to make the two operands
have the same type. Section 6.5.16 doesn't need special wording for null
pointer constants; the right operand is always converted to the type of
the left operand for assignment operators.

That's not a coincidence, or an oversight: there's no other operators
where it serves any useful purpose to allow null pointer constants as
operands. That's not quite true: function call operators also need to
convert null pointer constants to the appropriate pointer type, but in
that case conversion to the parameter's type is specified for all
prototyped arguments, whether or not they are null pointer constants.
Such implicit conversions most emphatically do NOT occur for
unprototyped arguments, including the variable arguments at the end of a
function declared as allowing such arguments. The expression
printf("%p", NULL) is not guaranteed to work as you might expect it to.
If the expansion of NULL is 0, it will be treated as an 'int', which is
the wrong type for %p (though it will work, by accident, on many platforms).

Section 6.5.3.2 describes the indirection operator, and the constraints
do not have an option allowing for general null pointer constants. Only
the ones (such as (void*)0) which actually have a pointer type are
allowed by the constraints (of course, the behavior is still undefined
if the operation is actually performed in that case). There is no
wording for that operator specifying the same kind of special handling
for null pointer constants that is described in 6.5.9p5 and 6.5.15p3.

t...@cs.ucr.edu

unread,
Nov 8, 2002, 9:20:29 AM11/8/02
to
In comp.std.c Joona I Palaste <pal...@cc.helsinki.fi> wrote:
[...]
+ I do not understand this. How can *0 be a syntactically and
+ contextually valid expression? The unary * operator means the thing
+ that is stored at the address given by the operand. Here, it's clear
+ that the thing is stored at address 0, but no one bothered to tell what
+ type of thing it is: char, int, long...

Good point. So, let's make that "*(int*)0" rather than "*0".

Tom Payne

Jun Woong

unread,
Nov 8, 2002, 10:01:33 AM11/8/02
to
"Richard Bos" <r...@hoekstra-uitgeverij.nl> wrote in message
news:3dcbc056...@news.nl.net...

> Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
>
> > t...@cs.ucr.edu wrote:
> > >>> int main(int argc, char **argv) { return argc && (*0 = 1); }
> > >>> ^
> > >>> assignment
> > >>>
> > >>> Assuming that argc can be zero, must the implementation translate
this
> > >>> program? I.e., is "*0" a legitimate lvalue here?
> >
> > >> No, it's a constraint violation. '0' doesn't have pointer type.
> >
> > > But it's a null pointer constant, so can be used as a pointer in at
> > > least some cases.
> >
> > Yes, but not this one. Look at the context (reinstated).
>
> That's the one-but-inner context. The _actual_ context is the
> dereference operator; _it_ requires a pointer context, and thus the 0 is
> interpreted as a null pointer constant, which is converted (at compile
> time, most likely) to an actual null pointer. This null pointer is then
> dereferenced.

Incorrect. You can never find the wording supporting your argument.
The unary operator doesn't qualify the context where a null pointer
constant is converted to a null pointer.

--
Jun, Woong (myco...@hanmail.net)
Dept. of Physics, Univ. of Seoul

Jun Woong

unread,
Nov 8, 2002, 10:04:39 AM11/8/02
to
<t...@cs.ucr.edu> wrote in message news:aqgh7d$egg$2...@glue.ucr.edu...

So.. what's your point? I don't see the connection between the subject
being discussed and your example. The interpretation of the Standard
doesn't change because of your example in this case.

Christian Bau

unread,
Nov 8, 2002, 10:08:48 AM11/8/02
to
In article <3dcbc056...@news.nl.net>,
r...@hoekstra-uitgeverij.nl (Richard Bos) wrote:

> That's the one-but-inner context. The _actual_ context is the
> dereference operator; _it_ requires a pointer context, and thus the 0 is
> interpreted as a null pointer constant, which is converted (at compile
> time, most likely) to an actual null pointer. This null pointer is then
> dereferenced.

Unless this has just been changed, null pointer constants become null
pointers only in a comparison using == or != (but not < <= > >=) and in
an assignment.

Jeremy Yallop

unread,
Nov 8, 2002, 10:25:53 AM11/8/02
to
Richard Bos wrote:
> Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
>
>> t...@cs.ucr.edu wrote:
>> >>> int main(int argc, char **argv) { return argc && (*0 = 1); }
>> >>> ^
>> >>> assignment
>> >>>
>> >>> Assuming that argc can be zero, must the implementation translate this
>> >>> program? I.e., is "*0" a legitimate lvalue here?
>>
>> >> No, it's a constraint violation. '0' doesn't have pointer type.
>>
>> > But it's a null pointer constant, so can be used as a pointer in at
>> > least some cases.
>>
>> Yes, but not this one. Look at the context (reinstated).
>
> That's the one-but-inner context. The _actual_ context is the
> dereference operator; _it_ requires a pointer context, and thus the 0 is
> interpreted as a null pointer constant, which is converted (at compile
> time, most likely) to an actual null pointer.

I'm sorry, but this is just plain wrong. The short proof is

What type does the expression `*0' have?

The long proof is:

A null pointer constant does not necessarily have pointer type. In
order to be used as a pointer it must be converted to a pointer
type(6.3.2.3). Such conversions take place either explicitly as a
result of casting (6.5.4), or implicitly as a result of assignment
(or equivalent) (6.5.16.1) or (in)equality comparison (6.5.9). In
contrast, the unary * operator does not induce any type conversion
but its argument is required to have pointer type (6.5.3.2).

I think that the source of your confusion is the expression `pointer
context' (which does not occur in the standard).

> if the compiler cannot be sure argc will never be 0, it _must_
> compile this program.

On the contrary, a diagnostic must be issued and there is no
obligation to complete translation.

Jeremy.

James Kuyper

unread,
Nov 8, 2002, 11:08:20 AM11/8/02
to

And in ?:

Dan Pop

unread,
Nov 8, 2002, 10:53:33 AM11/8/02
to

>In message <3DCAC92C...@null.net>, Douglas A. Gwyn
><DAG...@null.net> writes
>>Bill Godfrey wrote:
>>> If reporting the snipped example as an error is broken,
>>> then I'll take broken over "fixed", thank you very much.
>>
>>Why? The program had perfectly reasonable, well-defined
>>properties, but that compiler refused to accept it. Now,
>>a *warning* about possible division by zero might be
>>useful, but not an outright refusal to compile.
>
>Not least because (if I understand the rules correctly) division by zero
>could result in a NaN and no reason for the program to be aborted.

I don't think that this is an option for integer division.

t...@cs.ucr.edu

unread,
Nov 8, 2002, 10:49:14 AM11/8/02
to
In comp.std.c Jun Woong <myco...@hanmail.net> wrote:
+ <t...@cs.ucr.edu> wrote in message news:aqgh7d$egg$2...@glue.ucr.edu...
+> In comp.std.c Joona I Palaste <pal...@cc.helsinki.fi> wrote:
+> [...]
+> + I do not understand this. How can *0 be a syntactically and
+> + contextually valid expression? The unary * operator means the thing
+> + that is stored at the address given by the operand. Here, it's clear
+> + that the thing is stored at address 0, but no one bothered to tell what
+> + type of thing it is: char, int, long...
+>
+> Good point. So, let's make that "*(int*)0" rather than "*0".

+ So.. what's your point? I don't see the connection between the subject
+ being discussed and your example. The interpretation of the Standard
+ doesn't change because of your example in this case.

I replaced "1/0" with "*(int*)0 = 3", because (IIRC) in past
discussions, some members of the standards committee have held that
any occurrence of "*(int*)0" renders a program incorrect, whether or
not that expression would ever get evaluated. (I don't see similar
adamance about occurrences of "1/0".)

Tom Payne

Blah

unread,
Nov 8, 2002, 11:10:10 AM11/8/02
to
*** post for FREE via your newsreader at post.newsfeed.com ***


<t...@cs.ucr.edu> wrote in message news:aqgmdq$f72$1...@glue.ucr.edu...

So some behavior is more undefined than others?


-----= Posted via Newsfeed.Com, Uncensored Usenet News =-----
http://www.newsfeed.com - The #1 Newsgroup Service in the World!
-----== 100,000 Groups! - 19 Servers! - Unlimited Download! =-----

Jun Woong

unread,
Nov 8, 2002, 11:20:09 AM11/8/02
to
<t...@cs.ucr.edu> wrote in message news:aqgmdq$f72$1...@glue.ucr.edu...

I don't see why they said that the expression which results just in
undefined behavior can prevents the translation of the program even
when it's not evaluated explicitly. Could anyone show me the reason?

Thanks in advance.

t...@cs.ucr.edu

unread,
Nov 8, 2002, 10:54:43 AM11/8/02
to
In comp.std.c Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:

+ Richard Bos wrote:
+> Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
+>
+>> t...@cs.ucr.edu wrote:
+>> >>> int main(int argc, char **argv) { return argc && (*0 = 1); }
+>> >>> ^
+>> >>> assignment
+>> >>>
+>> >>> Assuming that argc can be zero, must the implementation translate this
+>> >>> program? I.e., is "*0" a legitimate lvalue here?
+>>
+>> >> No, it's a constraint violation. '0' doesn't have pointer type.
+>>
+>> > But it's a null pointer constant, so can be used as a pointer in at
+>> > least some cases.
+>>
+>> Yes, but not this one. Look at the context (reinstated).
+>
+> That's the one-but-inner context. The _actual_ context is the
+> dereference operator; _it_ requires a pointer context, and thus the 0 is
+> interpreted as a null pointer constant, which is converted (at compile
+> time, most likely) to an actual null pointer.
+
+ I'm sorry, but this is just plain wrong. The short proof is
+
+ What type does the expression `*0' have?
+
+ The long proof is:
+
+ A null pointer constant does not necessarily have pointer type. In
+ order to be used as a pointer it must be converted to a pointer
+ type(6.3.2.3). Such conversions take place either explicitly as a
+ result of casting (6.5.4), or implicitly as a result of assignment
+ (or equivalent) (6.5.16.1) or (in)equality comparison (6.5.9). In
+ contrast, the unary * operator does not induce any type conversion
+ but its argument is required to have pointer type (6.5.3.2).
+
+ I think that the source of your confusion is the expression `pointer
+ context' (which does not occur in the standard).
+
+> if the compiler cannot be sure argc will never be 0, it _must_
+> compile this program.
+
+ On the contrary, a diagnostic must be issued and there is no
+ obligation to complete translation.

Agreed. The mistake was mine -- I should have written "*(int*)0"
rather than "*0".

Tom Payne

James Kuyper

unread,
Nov 8, 2002, 11:32:30 AM11/8/02
to
Jun Woong wrote:
...

> I don't see why they said that the expression which results just in
> undefined behavior can prevents the translation of the program even
> when it's not evaluated explicitly. Could anyone show me the reason?

It's entirely an issue about what "use" means. If a program that
textually contains a construct is considered to "use" it, then the
behavior is undefined. If a construct is used only if the code
containing it is actually executed, then the behavior is defined, as
long as we can avoid executing that expression. Personally, I'd say the
meaning of "use" is unclear. However, the committee's DR resolution you
cited earlier came down on the side of the second interpretation. Some
people participating in this thread have not paid any attention to that
citation yet.

There's also a legitimate issue about whether a C90 ruling, which was
not implemented by appropriate clarifying textual changes to C99, can be
considered to apply to C99. If you believe that the DR resolution merely
explained the meaning, rather than clarifying something that was
inherently unclear, then it would follow that there was no need for such
textual changes.

Jun Woong

unread,
Nov 8, 2002, 11:57:57 AM11/8/02
to
"James Kuyper" <kuy...@saicmodis.com> wrote in message
news:3DCBE71E...@saicmodis.com...

Thanks very much for your very comprehensive explanation.

I beleve that the DR resolution explained the meaning as many other
DRs do so. As I know, there are more DRs just which explain the
meaning of the wording in question than which change the text of the
Standard via TCs.

Anyway, according to your and Clive's posting, we have to ask the
Committee validity of all C90 DRs not to make the change of the text
before we decide whether it can apply to C99. :(

Why didn't they clarify those things even if the charter says that
the revision reflects them? This is what I always complain of.

Thanks.

Dan Pop

unread,
Nov 8, 2002, 12:29:39 PM11/8/02
to

>There's also a legitimate issue about whether a C90 ruling, which was
>not implemented by appropriate clarifying textual changes to C99, can be
>considered to apply to C99. If you believe that the DR resolution merely
>explained the meaning, rather than clarifying something that was
>inherently unclear, then it would follow that there was no need for such
>textual changes.

Isn't the very existence of the DR proof enough that the standard was not
clear enough?

James Kuyper

unread,
Nov 8, 2002, 1:03:52 PM11/8/02
to
Dan Pop wrote:
>
> In <3DCBE71E...@saicmodis.com> James Kuyper <kuy...@saicmodis.com> writes:
...

> Isn't the very existence of the DR proof enough that the standard was not
> clear enough?

In itself, the existence of a DR doesn't prove that there's any
legitimate reason to be unsure about the meaning of the specified aspect
of the standard. Submitters can have an arbitrarily poor excuse for
submitting a DR. In the past, the Committee has sometimes responded to
DRs which it felt were poorly justified by saying "the standard is clear
enough".

I have to say that any such response is inherently insulting; and
correspondingly inappropriate unless the insult is richly deserved (and
questionable even in that case). Particularly when, as has sometimes
been the case, the response fails to identify which answer it is that
the committee considers so obvious. Even if the standard is perfectly
clear on an issue, and the submitter is a complete idiot for not
recognizing that fact, the submitter did in fact fail to recognize that
fact, and therefore needs help.

Jun Woong

unread,
Nov 8, 2002, 1:23:47 PM11/8/02
to
"Dan Pop" <Dan...@cern.ch> wrote in message
news:aqgsa3$kd$1...@sunnews.cern.ch...

I don't think so. AFAICK, the Committee is obliged to discuss and to
response all of DRs submitted. From C90 DRs which have been responsed,
we can know the fact that the submitters sometimes misunderstand the
clear wording which can be obtained by more elaborated reading. Of
course, it'd be useful to reflect those DRs which disclose the obscure
aspects of the Standard into the next revision even if they don't
qualify TCs, I believe.

t...@cs.ucr.edu

unread,
Nov 8, 2002, 6:29:35 PM11/8/02
to
In comp.std.c Jun Woong <myco...@hanmail.net> wrote:
+ <t...@cs.ucr.edu> wrote in message news:aqgmdq$f72$1...@glue.ucr.edu...
+> In comp.std.c Jun Woong <myco...@hanmail.net> wrote:
+> + <t...@cs.ucr.edu> wrote in message news:aqgh7d$egg$2...@glue.ucr.edu...
+> +> In comp.std.c Joona I Palaste <pal...@cc.helsinki.fi> wrote:
+> +> [...]
+> +> + I do not understand this. How can *0 be a syntactically and
+> +> + contextually valid expression? The unary * operator means the thing
+> +> + that is stored at the address given by the operand. Here, it's clear
+> +> + that the thing is stored at address 0, but no one bothered to tell
+ what
+> +> + type of thing it is: char, int, long...

+> +>
+> +> Good point. So, let's make that "*(int*)0" rather than "*0".
+>
+> + So.. what's your point? I don't see the connection between the subject
+> + being discussed and your example. The interpretation of the Standard
+> + doesn't change because of your example in this case.
+>
+> I replaced "1/0" with "*(int*)0 = 3", because (IIRC) in past
+> discussions, some members of the standards committee have held that
+> any occurrence of "*(int*)0" renders a program incorrect, whether or
+> not that expression would ever get evaluated. (I don't see similar
+> adamance about occurrences of "1/0".)
+>
+
+ I don't see why they said that the expression which results just in
+ undefined behavior can prevents the translation of the program even
+ when it's not evaluated explicitly. Could anyone show me the reason?

FWIW, I found the thread to which I referred. It was Oct 29, 2001, in
comp.std.c++, and entitled "Is *(int*)0 an lvalue?".

Tom Payne

Jun Woong

unread,
Nov 8, 2002, 10:45:40 PM11/8/02
to
<t...@cs.ucr.edu> wrote in message news:aqhhcv$i19$1...@glue.ucr.edu...

> In comp.std.c Jun Woong <myco...@hanmail.net> wrote:
> + <t...@cs.ucr.edu> wrote in message news:aqgmdq$f72$1...@glue.ucr.edu...
[...]

> +>
> +> I replaced "1/0" with "*(int*)0 = 3", because (IIRC) in past
> +> discussions, some members of the standards committee have held that
> +> any occurrence of "*(int*)0" renders a program incorrect, whether or
> +> not that expression would ever get evaluated. (I don't see similar
> +> adamance about occurrences of "1/0".)
> +>
> +
> + I don't see why they said that the expression which results just in
> + undefined behavior can prevents the translation of the program even
> + when it's not evaluated explicitly. Could anyone show me the reason?
>
> FWIW, I found the thread to which I referred. It was Oct 29, 2001, in
> comp.std.c++, and entitled "Is *(int*)0 an lvalue?".
>

After reading it roughly, I can see no more authoritative and
persuasive answer in the thread than the DRs I cited.

Douglas A. Gwyn

unread,
Nov 9, 2002, 12:44:06 AM11/9/02
to
Francis Glassborow wrote:
> Not least because (if I understand the rules correctly)
> division by zero could result in a NaN and no reason for
> the program to be aborted.

I don't think we allowed for NaNs in integer arithmetic,
but in some hypothetical implementation padding bits
could be used to encode them. Being undefined behavior,
it could happen.

Douglas A. Gwyn

unread,
Nov 9, 2002, 12:46:37 AM11/9/02
to
Joona I Palaste wrote:
> I do not understand this. How can *0 be a syntactically and
> contextually valid expression? The unary * operator means the thing
> that is stored at the address given by the operand. Here, it's clear
> that the thing is stored at address 0, but no one bothered to tell what
> type of thing it is: char, int, long...

You're right: it was a spurious argument, and noting that
there is no specific associated type is one way to see that.

Douglas A. Gwyn

unread,
Nov 9, 2002, 12:48:22 AM11/9/02
to
t...@cs.ucr.edu wrote:
> Good point. So, let's make that "*(int*)0" rather than "*0".

So what? It's no different from 1/0: undefined behavior
occurs if and only if that (sub)expression is evaluated.

Douglas A. Gwyn

unread,
Nov 9, 2002, 12:55:04 AM11/9/02
to
Dan Pop wrote:
> Isn't the very existence of the DR proof enough that
> the standard was not clear enough?

No. There are many causes for DR questions, and some of
them clearly come under the category of nit-picking where
nobody argues that responsible programmers or implementors
would misunderstand the intent.

Douglas A. Gwyn

unread,
Nov 9, 2002, 12:59:53 AM11/9/02
to
James Kuyper wrote:
> ... In the past, the Committee has sometimes responded to

> DRs which it felt were poorly justified by saying "the
> standard is clear enough".

That originated in the one-line summary macros I used when
I was the keeper of the DRs. During my reign the policy
was to follow the summary by a more detailed explanation.
But in cases where the DR submitter has not indicated any
misunderstanding of the intent and merely suggests wording
that he prefers, no additional explanation is necessary
once we indicate that we reconsidered the wording and
still find no need to make any change.

t...@cs.ucr.edu

unread,
Nov 9, 2002, 7:34:25 AM11/9/02
to
In comp.std.c Douglas A. Gwyn <DAG...@null.net> wrote:
+ t...@cs.ucr.edu wrote:
+> Good point. So, let's make that "*(int*)0" rather than "*0".
+
+ So what? It's no different from 1/0: undefined behavior
+ occurs if and only if that (sub)expression is evaluated.

I agree. The "*(int*)0" version, however, has drawn adamant and
authoritative insistance that conforming implementations should not,
under any circumstance, be required to accept such constructs, e.g.,
Francis Glassborow wrote:

... You seem to be claiming that a compiler must accept:

if(foo()) *(int *)0 = 1;

even though it can only determine that either the line is a waste of
space or it generates undefined behaviour depending on the value of
foo(). I maintain that is unreasonable.

FWIW, I maintain the total opposite, i.e., that it would be
unreasonable not to require the "acceptance" of

if(foo()) *(int *)0 = 1;

if there's any possibility that foo() might return zero. The
same goes for "if(foo()) 1/0;".

Tom Payne

Dan Pop

unread,
Nov 11, 2002, 5:21:15 AM11/11/02
to

This is a purely subjective judgment. The kind of judgment that is
responsible for the very existence of this thread: if the answers to
the relevant C89 DRs had been incorporated in the text of C99, the issue
would have been clarified for anyone having access to the standard.

Instead of that, to find the answer, one has to dig into the DRs submitted
against C89, whose relevance to C99 is highly debatable and debated.

Richard Bos

unread,
Nov 11, 2002, 6:57:14 AM11/11/02
to
t...@cs.ucr.edu wrote:

> In comp.std.c Richard Bos <r...@hoekstra-uitgeverij.nl> wrote:
> + That's the one-but-inner context. The _actual_ context is the
> + dereference operator; _it_ requires a pointer context, and thus the 0 is
> + interpreted as a null pointer constant, which is converted (at compile

> + time, most likely) to an actual null pointer. This null pointer is then
> + dereferenced.
> + As a result, this program is syntactically correct, and invokes
> + undefined behaviour only when argc != 0. If the compiler can determine
> + that argc will always be positive (for example, if it knows it will
> + always be able to supply argv[0]), it is AFAICT allowed not to compile
> + it; but if the compiler cannot be sure argc will never be 0, it _must_
> + compile this program.
>
> That's exactly how I see it. It follows, however, that "*0" is an
> lvalue even though it does not designate an object. Lots of folks
> seems to balk at that.

Syntactically, it _is_ an lvalue. Syntactically, *garbage_pointer is
also an lvalue. An lvalue does not necessarily designate a _valid_
object; only lvalues whose generation does not invoke UB are guaranteed
to do that. An lvalue which is invalid can designate something that
_looks_ like an object, but is invalid.

Richard

Bill Godfrey

unread,
Nov 11, 2002, 9:57:13 AM11/11/02
to
"Douglas A. Gwyn" <DAG...@null.net> wrote:

[BillG]


> > If reporting the snipped example as an error is broken,
> > then I'll take broken over "fixed", thank you very much.

> Why? The program had perfectly reasonable, well-defined
> properties, but that compiler refused to accept it. Now,
> a *warning* about possible division by zero might be
> useful, but not an outright refusal to compile.

IMO, code snippets like 1/0 are "bad", and even if the code will never run,
the fact it is there is still a bad thing.

A good compiler should detect a constant expression with a value of zero
appearing on the right of a / operator. For a compiler to let (1/0) pass,
even with just a warning, it would have to generate some code for the
result of this expression. It's already done the workload of detecting the
x/0 and now it needs to do some more.

Runtime error message? Core dump? 0?

Nah, upgrade the warning to an error and abandon the compile. Let the
programmer sort out the bad code.

I'd rather the compiler makers spent thier time on useful stuff.

All IMO.

Bill, no really, all IMO.

Christian Bau

unread,
Nov 11, 2002, 10:51:09 AM11/11/02
to
In article <20021111095713.663$e...@newsreader.com>,
billg-...@bacchae.f9.co.uk.invalid (Bill Godfrey) wrote:

> "Douglas A. Gwyn" <DAG...@null.net> wrote:
>
> [BillG]
> > > If reporting the snipped example as an error is broken,
> > > then I'll take broken over "fixed", thank you very much.
>
> > Why? The program had perfectly reasonable, well-defined
> > properties, but that compiler refused to accept it. Now,
> > a *warning* about possible division by zero might be
> > useful, but not an outright refusal to compile.
>
> IMO, code snippets like 1/0 are "bad", and even if the code will never run,
> the fact it is there is still a bad thing.
>
> A good compiler should detect a constant expression with a value of zero
> appearing on the right of a / operator. For a compiler to let (1/0) pass,
> even with just a warning, it would have to generate some code for the
> result of this expression. It's already done the workload of detecting the
> x/0 and now it needs to do some more.

Example:

Somewhere in a header file I wrote either:

#define NUMBER_OF_ITEMS 10

or

#define NUMBER_OF_ITEMS 0

Shouldn't I be allowed to write this without a warning:

if (NUMBER_OF_ITEMS > 0) {
int x = 100 / NUMBER_OF_ITEMS;
int y = x * NUMBER_OF_ITEMS;

printf ("%d %d\n", x, y);
}

After all, if I changed the header file to

extern int NUMBER_OF_ITEMS;

then my code snippet would be perfectly fine (unless there is some
stupid mistake in it).

lawrenc...@eds.com

unread,
Nov 11, 2002, 4:19:27 PM11/11/02
to
In comp.std.c Jun Woong <myco...@hanmail.net> wrote:
>
> I beleve that the DR resolution explained the meaning as many other
> DRs do so. As I know, there are more DRs just which explain the
> meaning of the wording in question than which change the text of the
> Standard via TCs.
[...]

> Why didn't they clarify those things even if the charter says that
> the revision reflects them? This is what I always complain of.

Because the committee is loathe to spend time on wording issues.
History shows that whenever we do, we end up spending an inordinate
amount of time for little, if any, improvement. During the revision
process, if someone proposed "better" wording and the committee (or at
least the editor) agreed that it was, indeed, better (remember that
clarity is, in general, subjective, not objective), it got used. In
cases where the standard just doesn't say what we meant and doesn't
contain sufficient hints for a highly-motivated reader to figure out the
intent we'll revise the wording, but otherwise we tend to leave it
alone.

-Larry Jones

Fortunately, that was our plan from the start. -- Calvin

lawrenc...@eds.com

unread,
Nov 11, 2002, 4:19:27 PM11/11/02
to
In comp.std.c James Kuyper <kuy...@saicmodis.com> wrote:
>
> In the past, the Committee has sometimes responded to
> DRs which it felt were poorly justified by saying "the standard is clear
> enough".
>
> I have to say that any such response is inherently insulting; and
> correspondingly inappropriate unless the insult is richly deserved (and
> questionable even in that case). Particularly when, as has sometimes
> been the case, the response fails to identify which answer it is that
> the committee considers so obvious. Even if the standard is perfectly
> clear on an issue, and the submitter is a complete idiot for not
> recognizing that fact, the submitter did in fact fail to recognize that
> fact, and therefore needs help.

The quality of the responses has unfortunately been quite variable.
We're trying to do a better job now than we have in the past, I hope
we're succeeding. "The standard is clear enough" may be poorly phrased;
the intended meaning is not "you're an idiot" but rather "it doesn't
seem to be causing mass confusion and we can't think of any better way
to say it right now".

-Larry Jones

I've got to start listening to those quiet, nagging doubts. -- Calvin

Douglas A. Gwyn

unread,
Nov 11, 2002, 7:30:59 PM11/11/02
to
Bill Godfrey wrote:
> IMO, code snippets like 1/0 are "bad", ...

Not when you're trying to test your divide-by-zero
exeption handler.

Bill Godfrey

unread,
Nov 12, 2002, 5:26:46 AM11/12/02
to
Christian Bau <christ...@freeserve.co.uk> wrote:

> Shouldn't I be allowed to write this without a warning:

> if (NUMBER_OF_ITEMS > 0) {
> int x = 100 / NUMBER_OF_ITEMS;
> int y = x * NUMBER_OF_ITEMS;

Damn! (I humbly withdraw the objection.)

Bill, reading his new copy of "101 ways to not look like an idiot".

James Kuyper

unread,
Nov 12, 2002, 9:40:40 AM11/12/02
to
lawrenc...@eds.com wrote:
...

> we're succeeding. "The standard is clear enough" may be poorly phrased;
> the intended meaning is not "you're an idiot" but rather "it doesn't
> seem to be causing mass confusion and we can't think of any better way
> to say it right now".

And as such, it's a useful thing to know; but as the sole answer to a DR
(which it has been, on occasion), it doesn't qualify as actually
answering the question.

--
James Kuyper
MODIS Level 1 Lead
Science Data Support Team
(301) 352-2150

lawrenc...@eds.com

unread,
Nov 12, 2002, 12:19:26 PM11/12/02
to
In comp.std.c James Kuyper <kuy...@saicmodis.com> wrote:
> lawrenc...@eds.com wrote:
> ...
>> we're succeeding. "The standard is clear enough" may be poorly phrased;
>> the intended meaning is not "you're an idiot" but rather "it doesn't
>> seem to be causing mass confusion and we can't think of any better way
>> to say it right now".
>
> And as such, it's a useful thing to know; but as the sole answer to a DR
> (which it has been, on occasion), it doesn't qualify as actually
> answering the question.

Indeed; which is why a number of committee members are now insisting
that, in general, when a DR asks specific questions, the committee
response contain answers to those questions. This is only "in general"
because there are lots of extenuating circumstances. For example, the
committee has in the past received DR's along the lines of:

Consider the following code:
...
Is there any undefined behavior here?

with no indication of what the actual issue is or what the author finds
suspect. Such DRs seem more like a game of "stump the committee" than
legitimate questions, although that was probably not the authors' intent
(we recognize that asking good questions is as difficult as providing
good answers). Nonetheless, the committee reserves the right to refuse
to play the game.

-Larry Jones

I keep forgetting that rules are only for little nice people. -- Calvin

0 new messages