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

Empty objects

3 views
Skip to first unread message

Dennis Ritchie

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
I just slipped a copy of the August draft to
Doug McIlroy, a long-time believer in handling
the end-cases properly. He writes me (and with
permission I post) his observations. We know
this is just putting the chicken into the fox-house
and it's not the time to rethink the issue from the start;
but this is usenet, after all. Observe that in referring
to malloc he is is not talking about an always-failing
version, rather that he would like malloc(0) to
succeed. Likewise int a[0] .

I'll point out (to his content) that the draft is more
explicit on the edge-case for the string functions
than the current standard.

Dennis

Doug's note:

Sigh. The new draft not only fails to fix the
mistake of allowing malloc(0) to fail unconditionally,
it compounds the error by forbidding VLA's to take
on length zero. For consistency (and efficiency)
the draft might well also emulate Fortran instead
of Algol in specifying the semantics of the for
statement, since it is useless to have the loop
work when the declaration doesn't in places like
this:
int a[n];
for(i=0; i<n; i++)
a[i] = 1;

To further discourage the bootless proliferation
of vacuous data structures, it would be well also to
forbid zero as an initializer for pointer variables.
The greatly reduced likelihood of empty lists and
trees would also argue for Fortran semantics in
loops like

for(q=p; *q; q=q->next)
...

Nick Maclaren

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
In article <35FF45...@bell-labs.com>,

Dennis Ritchie <d...@bell-labs.com> wrote:
>I just slipped a copy of the August draft to
>Doug McIlroy, a long-time believer in handling
>the end-cases properly. He writes me (and with
>permission I post) his observations. We know
>this is just putting the chicken into the fox-house
>and it's not the time to rethink the issue from the start;
>but this is usenet, after all. Observe that in referring
>to malloc he is is not talking about an always-failing
>version, rather that he would like malloc(0) to
>succeed. Likewise int a[0] .

Hmm. Tricky. Now, how would I implement that? I don't think that
it is always feasible, at least with acceptable efficiency, and
therefore I don't think it should be required. Consider the case
when there is NO free space.

Each call to malloc and int[0] has to produce a unique address,
guaranteed not to compare equal to any real data pointer. But it
has to be a data pointer. Now, if the whole of the data address
space is allocated with real data pointers, it can't be done. So
an implementation would have to increase the size of pointers
just to allow this facility.


Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Email: nm...@cam.ac.uk
Tel.: +44 1223 334761 Fax: +44 1223 334679

Larry Jones

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
Nick Maclaren wrote:
>
> Hmm. Tricky. Now, how would I implement that? I don't think that
> it is always feasible, at least with acceptable efficiency, and
> therefore I don't think it should be required. Consider the case
> when there is NO free space.

I think you misunderstand -- Doug isn't arguing that malloc(0) and a[0]
should succeed in all cases, he's arguing that they shouldn't be allowed
to fail gratuitously as they currently are. I happen to agree with him,
as do other committee members. Unfortunately, none of us were
sufficiently motivated to do anthing about it for this revisions of the
standard, particularly since we fought the battle last time and lost.

-Larry Jones

If I get a bad grade, it'll be YOUR fault for not doing the work for me!
-- Calvin

Vik Heyndrickx

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
Nick Maclaren wrote:
> Each call to malloc and int[0] has to produce a unique address,
> guaranteed not to compare equal to any real data pointer.

I fail to see why that should also be a requirement for zero-sized
objects, since I think that dereferencing a pointer to such an object
yield undefined behaviour.
Just to elaborate a little further: If such unicity were not required, a
unique address could serve for all zero-sized objects; why couldn't we
use NULL for that (aka 0).

After all what's different from the "int i = 0, j; j = 5/i;" case.

> But it
> has to be a data pointer. Now, if the whole of the data address
> space is allocated with real data pointers, it can't be done.

Why couldn't the compiler create objects of size 1 whatever's and let
the user believe it is 0 sized.

> So
> an implementation would have to increase the size of pointers
> just to allow this facility.

I'll probably have missed something.

--
\ Vik /-_-_-_-_-_-_/
\___/ Heyndrickx /
\ /-_-_-_-_-_-_/ Knight in the Order of the Unsigned Types


Dave Hansen

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
On Wed, 16 Sep 1998 18:29:30 +0200, Vik Heyndrickx
<Vik.Hey...@rug.ac.be> wrote:

>Nick Maclaren wrote:
>> Each call to malloc and int[0] has to produce a unique address,
>> guaranteed not to compare equal to any real data pointer.
>
>I fail to see why that should also be a requirement for zero-sized
>objects, since I think that dereferencing a pointer to such an object
>yield undefined behaviour.

Because you don't have to dereference pointers to compare them. For
example:

extern size_t get_size(void); /* might return zero */

char *p1 = malloc(get_size());
assert(p1 != NULL);

char *p2 = malloc(get_size());
assert(p2 != NULL);

assert(p1 != p2);

>Just to elaborate a little further: If such unicity were not required, a
>unique address could serve for all zero-sized objects; why couldn't we
>use NULL for that (aka 0).

Because then we wouldn't be able to tell whether malloc failed or not
when allocating a zero-sized object. NULL can't simultaneously
indicate an invalid pointer and point to a valid zero-sized object.

>
>After all what's different from the "int i = 0, j; j = 5/i;" case.

I'm not sure I follow...

The difference is that you occasionally might like to allocate a
buffer with zero size. I've never (really) wanted to divide 5 (or any
other number) by zero.

An example from a few years ago: I worked on an interpreter (for C)
that calculated how much static data memory was required to run the
interpreted program, and then allocated it. The code looked something
like this (_much_ simplified):

data_size = program_info.static_data_size;
static_data_ptr = malloc(data_size);
if (static_data_ptr == NULL)
die_horrible_death_with_error_message("out of memory");

The above code could (but may not) fail if req_size returned zero.
But it is perfectly reasonable to interpret a program that requires no
static data area.

Yes, the fix is simple, but it's galling: since there was no static
data defined in the interpreted program, the static data buffer would
never be accessed. A zero-sized buffer is perfectly reasonable.

Actually, the code in question used realloc rather than malloc, and
here the situation is even worse: if the specified size is zero, the
return value from malloc depends on whether the passed pointer is NULL
or not. In this case, a program using no static memory would run fine
the first time, but fail the second, run fine the third time, but fail
the forth, etc. But that's another issue...

>
>> But it
>> has to be a data pointer. Now, if the whole of the data address
>> space is allocated with real data pointers, it can't be done.
>
>Why couldn't the compiler create objects of size 1 whatever's and let
>the user believe it is 0 sized.

Yes, this is what I (for one, anyway) would like to see. Call the one
byte buffer management overhead -- it's allowed.

All IMHO. Regards,

-=Dave
Just my (10-010) cents
I can barely speak for myself, so I certainly can't speak for B-Tree.
Change is inevitable. Progress is not.

Steve Chapel

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
Dennis Ritchie wrote:

> ...
> Doug [McIlroy's] note:


>
> Sigh. The new draft not only fails to fix the
> mistake of allowing malloc(0) to fail unconditionally,
> it compounds the error by forbidding VLA's to take
> on length zero. For consistency (and efficiency)
> the draft might well also emulate Fortran instead
> of Algol in specifying the semantics of the for
> statement, since it is useless to have the loop
> work when the declaration doesn't in places like
> this:
> int a[n];
> for(i=0; i<n; i++)
> a[i] = 1;

I ran into this self same problem using C++ and two different versions
of malloc, one re-entrant for use with multitasking, and the other
the standard, non-re-entrant version that came with the compiler.

In C++,
n = 0;
int *a = new int[n]; // like malloc(0 * sizeof(int))
is perfectly legal and returns a non-null pointer distinct from all
other pointers. I experienced the problem in a program where I was
allocating a triangular array, and the first row contained zero
columns. One version of the memory allocator allowed allocation of
zero bytes, and the other didn't. It took me a while to figure
out why the compiler's allocator kept running out of memory when I
was creating this triangular array. The problem was that the
allocator was returning NULL when I asked for zero bytes,
which my program and I mistook for lack of available memory.

I'm not suggesting that we make C into C++, but I would like to see
them become more similar in how they handle exceptional cases. This
would mean that malloc(0) would also return a non-null pointer distinct
from all other currently malloc'ed pointers, and that free(NULL) would
also always succeed.
--
Mr. Hankey... the Christmas poo... he loved me... I love you.
Therefore, vicariously, he loved you...

Douglas A. Gwyn

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
Larry Jones wrote:
> ... Unfortunately, none of us were

> sufficiently motivated to do anthing about it for this revisions of the
> standard, particularly since we fought the battle last time and lost.

It's not so much the lack of motivation as not having found
an overwhelming counterargument to the problems pointed out
by the "no zero-sized objects in C" crowd, for example that
#define Number_of_elements(a) (sizeof(a)/sizeof(a)[0])
breaks when 0-sized elements are allowed. That example is
indicative of a whole nest of problems; basically the address
arithmetic degenerates to a 0-dimensional subspace rather
than the usual 1-dimensional space.

I personally want C to support 0-sized objects, and once
served as "point of contact" for the topic, but virtually
nobody contacted the 0-sized-object POC, so I gather there
is not sufficient demand to justify the effort.

Norman Yarvin

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
"Douglas A. Gwyn" <DAG...@null.net> wrote:

>It's not so much the lack of motivation as not having found
>an overwhelming counterargument to the problems pointed out
>by the "no zero-sized objects in C" crowd, for example that
> #define Number_of_elements(a) (sizeof(a)/sizeof(a)[0])
>breaks when 0-sized elements are allowed.

Why is that a problem? True, if someone writes such a macro, they won't
be able to use it on arrays with zero-size elements. But why, as a
practical matter, would this bother anybody? Those who want to use such
a macro, and who absolutely insist that it be applicable to every array
they use, can avoid creating arrays of zero-size elements. Even when
dealing with other people's code, they would almost never run into
problems, because there is hardly ever a reason to create arrays of
zero-size elements. And on the occasions, rare almost to the point of
nonexistence, when they did run into one, and did use that macro, it
would produce an easily fixed compile-time error.

> That example is
>indicative of a whole nest of problems; basically the address
>arithmetic degenerates to a 0-dimensional subspace rather
>than the usual 1-dimensional space.

That doesn't sound like a problem, in general. It's not as if the
compiler would have to produce special-case code to be able to handle
objects of zero size.

>I personally want C to support 0-sized objects, and once
>served as "point of contact" for the topic, but virtually
>nobody contacted the 0-sized-object POC, so I gather there
>is not sufficient demand to justify the effort.

There is never much visible demand for removing a single minor nuisance.

I suppose this is the advantage of having someone like Dennis define a
language, rather than having a committee do it: he can remove minor
nuisances without much effort.


--
Norman Yarvin yar...@cs.yale.edu

Paul Eggert

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

>[We haven't] found


>an overwhelming counterargument to the problems pointed out
>by the "no zero-sized objects in C" crowd, for example that
> #define Number_of_elements(a) (sizeof(a)/sizeof(a)[0])
>breaks when 0-sized elements are allowed.

That's an unsound reason to prohibit zero-sized elements,
and McIlroy already made a strong counterargument against it,
albeit ironically and by analogy:

To further discourage the bootless proliferation
of vacuous data structures, it would be well also to
forbid zero as an initializer for pointer variables.

Let me take McIlroy's argument one step further. Suppose the
C Standard disallowed all null pointers, and suppose there was a
"no null pointers in C" crowd that didn't want to add null pointers
to the standard, on the grounds that this would break existing programs
that assumed that one could always dereference a pointer.

This hypothetical "no null pointers in C" crowd would not be moved by
the utility of extending the language to allow null pointers. They
would consider their existing idioms to be more important than the
overall utility and consistency of the language.

The analogy is quite close.

Douglas A. Gwyn

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
Norman Yarvin wrote:
> Why is that a problem? True, if someone writes such a macro, they won't
> be able to use it on arrays with zero-size elements. But why, as a
> practical matter, would this bother anybody? Those who want to use such
> a macro, and who absolutely insist that it be applicable to every array
> they use, can avoid creating arrays of zero-size elements.

But then having 0-sized objects isn't such a slick idea, is it?
Doug M.'s argument is that they fit naturally into 0-trip loop
processing, but that's only true for 0-long arrays of nonzero-sized
elements. The problem is, once you have 0-long arrays you also
have 0-sized objects, with troublesome address arithmetic properties.

> ... there is hardly ever a reason to create arrays of
> zero-size elements.

That argument could be made for 0-length arrays as well.

Actually, there *are* fairly natural occasions for both.

Larry Jones

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
Paul Eggert wrote:
>
> Let me take McIlroy's argument one step further. Suppose the
> C Standard disallowed all null pointers, and suppose there was a
> "no null pointers in C" crowd that didn't want to add null pointers
> to the standard, on the grounds that this would break existing programs
> that assumed that one could always dereference a pointer.

You mean you can't?!? Has anyone told those guys at Berkeley? ;-)

> This hypothetical "no null pointers in C" crowd would not be moved by
> the utility of extending the language to allow null pointers. They
> would consider their existing idioms to be more important than the
> overall utility and consistency of the language.

Kind of like the "no long long" crowd?

-Larry Jones

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

Peter Seebach

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
In article <6tntsq$cvo$1...@pegasus.csx.cam.ac.uk>,

Nick Maclaren <nm...@cus.cam.ac.uk> wrote:
>Hmm. Tricky. Now, how would I implement that? I don't think that
>it is always feasible, at least with acceptable efficiency, and
>therefore I don't think it should be required. Consider the case
>when there is NO free space.

Well, then malloc fails for the same reason it would for larger values.
I like this; I *want* malloc(0) to DTRT, which is, IMHO, allocate a pointer
to at least zero bytes.

Of course, you can't do it with realloc then.

>Each call to malloc and int[0] has to produce a unique address,

>guaranteed not to compare equal to any real data pointer. But it


>has to be a data pointer. Now, if the whole of the data address

>space is allocated with real data pointers, it can't be done. So


>an implementation would have to increase the size of pointers
>just to allow this facility.

No. Then it would just have a bit less space for other objects. We know
that objects can have padding bytes between them...

-s
--
Copyright 1998, All rights reserved. Peter Seebach / se...@plethora.net
C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon!
Seeking interesting programming projects. Not interested in commuting.
Visit my new ISP <URL:http://www.plethora.net/> --- More Net, Less Spam!

Peter Seebach

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
In article <35FFF913...@utilicom.com>,

Steve Chapel <sch...@utilicom.com> wrote:
>I'm not suggesting that we make C into C++, but I would like to see
>them become more similar in how they handle exceptional cases. This
>would mean that malloc(0) would also return a non-null pointer distinct
>from all other currently malloc'ed pointers, and that free(NULL) would
>also always succeed.

free(NULL) is already okay in C89.

Nick Maclaren

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to

In article <OmbM1.340$Ge.8...@ptah.visi.com>, se...@plethora.net (Peter Seebach) writes:
|> In article <6tntsq$cvo$1...@pegasus.csx.cam.ac.uk>,
|> Nick Maclaren <nm...@cus.cam.ac.uk> wrote:
|> >Hmm. Tricky. Now, how would I implement that? I don't think that
|> >it is always feasible, at least with acceptable efficiency, and
|> >therefore I don't think it should be required. Consider the case
|> >when there is NO free space.
|>
|> Well, then malloc fails for the same reason it would for larger values.
|> I like this; I *want* malloc(0) to DTRT, which is, IMHO, allocate a pointer
|> to at least zero bytes.

That is not what I understood the proposal to be, but is apparently
what it meant. Yes, implementing malloc(0) just like malloc(1)
but one byte less isn't hard :-)

There are problems with it, but they are almost all because other
aspects of the language need sorting out for zero-sized objects.
I believe that C9X has tackled most of them, though I am not sure
it has tackled all.

Paul Eggert

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
Larry Jones <larry...@sdrc.com> writes:

>> This hypothetical "no null pointers in C" crowd would not be moved by
>> the utility of extending the language to allow null pointers. They
>> would consider their existing idioms to be more important than the
>> overall utility and consistency of the language.

>Kind of like the "no long long" crowd?

The "no long long" crowd is different, because they are objecting to
a change in the language that breaks existing real-world programs.
For example, if S is of type size_t, then the code

printf ("%lu", (unsigned long) S);

is broken by the introduction of types longer than long.

In contrast, the "no size-0 objects" crowd (along with my hypothetical
"no null pointers in C" crowd) cannot object on the basis of breaking
existing real-world programs. Even if size-0 objects are allowed,
the idiom (sizeof(x)/sizeof(*(x))) will continue to work in existing
programs. And if a program works in a hypothetical variant of C that
does not allow null pointers, then the program will not break simply
because the hypothetical standard is changed to allow null pointers.

Dave Hansen

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
On 17 Sep 1998 17:30:35 GMT, nm...@cus.cam.ac.uk (Nick Maclaren) wrote:

>That is not what I understood the proposal to be, but is apparently
>what it meant. Yes, implementing malloc(0) just like malloc(1)
>but one byte less isn't hard :-)

No, but then you've got to fix realloc. Consider

p1 = realloc(p2, 0);

If p2 == NULL, realloc behaves like malloc, i.e., returns a valid
pointer to zero bytes. However, if p2!=NULL, realloc frees the buffer
pointed to by p2 and returns NULL.

Consider the loop (simplified from an interpreter I worked on in the
past)

char *buf = NULL;

while (!done)
{
size_t sz = calc_sz();
buf = realloc(buf, sz);
if (buf == NULL)
die();
use(buf);
}

Note that if calc_sz returns zero, use will not dereference buf. This
works fine as long as calc_sz never returns zero twice in a row.

Peter Curran

unread,
Sep 17, 1998, 3:00:00 AM9/17/98
to
On 17 Sep 1998 12:48:31 -0700, egg...@twinsun.com (Paul Eggert) wrote:

>Larry Jones <larry...@sdrc.com> writes:
>
>>> This hypothetical "no null pointers in C" crowd would not be moved by
>>> the utility of extending the language to allow null pointers. They
>>> would consider their existing idioms to be more important than the
>>> overall utility and consistency of the language.
>
>>Kind of like the "no long long" crowd?
>
>The "no long long" crowd is different, because they are objecting to
>a change in the language that breaks existing real-world programs.

<snip>

And. of course, because the needs of the "long long" crowd can be
achieved elsewise. (You knew I couldn't ignore this, didn't you?)

--
Peter Curran pcu...@acm.gov (chg gov=>org)

Douglas A. Gwyn

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Paul Eggert wrote:
> Let me take McIlroy's argument one step further. Suppose the
> C Standard disallowed all null pointers, and suppose there was a
> "no null pointers in C" crowd that didn't want to add null pointers
> to the standard, on the grounds that this would break existing programs
> that assumed that one could always dereference a pointer.

I think you're straining whatever analogy there might be.
Null pointers are *already* in C, imperfectly by the way, but zero-sized
objects aren't;
it's status quo in one case, innovation in the other.
It is up to the innovator to "sell" the idea; some of us have tried in
the past, but haven't succeeded.

Norman Yarvin

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
"Douglas A. Gwyn" <DAG...@null.net> wrote:
>Norman Yarvin wrote:
>> Why is that a problem? True, if someone writes such a macro, they won't
>> be able to use it on arrays with zero-size elements. But why, as a
>> practical matter, would this bother anybody? Those who want to use such
>> a macro, and who absolutely insist that it be applicable to every array
>> they use, can avoid creating arrays of zero-size elements.
>
>But then having 0-sized objects isn't such a slick idea, is it?

It's not the slickest idea in the world, but the point of a language is
not to be slick, but rather to be useful. Having zero-sized objects has
the practical advantage that one doesn't need to write special-case code
to handle things like the length of a dynamically allocated input buffer
being zero. Its practical disadvantages seem minor by comparison.

>Doug M.'s argument is that they fit naturally into 0-trip loop
>processing, but that's only true for 0-long arrays of nonzero-sized
>elements. The problem is, once you have 0-long arrays you also
>have 0-sized objects, with troublesome address arithmetic properties.

It's not a problem from the language definition point of view; the
language definition can state that taking the difference between two
pointers to zero-sized objects is an undefined operation. (The only case
where the compiler could not catch it would be where those objects were
variable-length arrays, sized at runtime.) With such a language
definition, there would be no need for the compiler to output
special-case code, so efficiency would not be a problem either.

Nor is it much of a problem from the programmer's point of view. He
would have to avoid that undefined operation; but he already has to avoid
plenty of other undefined operations, and there is nothing insidious
about this one. There is one new obligation that it would impose on the
programmer: if he were writing a routine which used pointers to variable
length arrays that might be of size zero, he would have to write it to
not take the differences of those pointers. This is always possible, by
using index arithmetic instead of pointer arithmetic; in many cases,
probably in most cases, it is the natural way to write the routine.
Alternatively, if he insisted on taking the differences of two pointers,
he would have to document the fact that the routine could not handle
objects of size zero, and perhaps put in an assertion to enforce it.
None of this would affect old code which does not use variable-length
arrays; nothing would have to be rewritten.


--
Norman Yarvin yar...@cs.yale.edu

Dik T. Winter

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Talking about empty objects, we just found that on many implementations
the call
bsearch(key, NULL, 0, size, compar);
crashes.

Is this behaviour allowed? (I see no reason for the behaviour, but
I am not interested in the reason, only whether an implementation
may do that.)
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

Francis Glassborow

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
In article <EzH6D...@cwi.nl>, Dik T. Winter <d...@cwi.nl> writes

>Talking about empty objects, we just found that on many implementations
>the call
> bsearch(key, NULL, 0, size, compar);
>crashes.
>
>Is this behaviour allowed? (I see no reason for the behaviour, but
>I am not interested in the reason, only whether an implementation
>may do that.)

I would think so. The second argument is supposed to be the address of
the first element of an array. Whatever else it might be NULL (by
definition) can never be that.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Larry Jones

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Paul Eggert wrote:
>
> The "no long long" crowd is different, because they are objecting to
> a change in the language that breaks existing real-world programs.

I *knew* I should have put another smiley in there -- my tongue was
firmly planted in my cheek when I wrote that, I didn't really mean to
reopen the long long discussion.

> In contrast, the "no size-0 objects" crowd (along with my hypothetical
> "no null pointers in C" crowd) cannot object on the basis of breaking
> existing real-world programs. Even if size-0 objects are allowed,
> the idiom (sizeof(x)/sizeof(*(x))) will continue to work in existing
> programs.

Not necessarily -- what if sizeof(*(x)) is also zero? If allowing a[n]
when n is zero makes sense (and I agree with Doug M. that it does),
then allowing a[n][m] when either (?) or both n and m are zero also
makes sense.

> And if a program works in a hypothetical variant of C that
> does not allow null pointers, then the program will not break simply
> because the hypothetical standard is changed to allow null pointers.

Are you serious? They get "broken" in exactly the same way as long long
"breaks" programs:

if (*p) { /*...*/ }

is no longer correct if p might be a null pointer, just like

printf("%lu", (unsigned long)sizeof x);

is no longer correct if size_t might be long long.

-Larry Jones

Sometimes I think the surest sign that intelligent life exists elsewhere
in the universe is that none of it has tried to contact us. -- Calvin

Larry Jones

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Dave Hansen wrote:
>
> No, but then you've got to fix realloc. Consider
>
> p1 = realloc(p2, 0);
>
> If p2 == NULL, realloc behaves like malloc, i.e., returns a valid
> pointer to zero bytes. However, if p2!=NULL, realloc frees the buffer
> pointed to by p2 and returns NULL.

It's already fixed -- that was never the committee's intent and the
wording in the most recent draft has been changed to clarify that the
implementation is free to change the size of the buffer in this case,
it is not required to free it and return NULL.

-Larry Jones

I don't think math is a science, I think it's a religion. -- Calvin

Larry Jones

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Dik T. Winter wrote:
>
> Talking about empty objects, we just found that on many implementations
> the call
> bsearch(key, NULL, 0, size, compar);
> crashes.
>
> Is this behaviour allowed? (I see no reason for the behaviour, but
> I am not interested in the reason, only whether an implementation
> may do that.)

I would say that it is, and that the code above is doubly undefined
because base has to point to the first element of an array (which NULL
doesn't do) and nmemb has to specify the number of elements in the
array (which can't be zero). Note that the string functions have
explicit text allowing for zero lengths (the absence of similar text
here implies that it's not allowed), but still require valid pointers.

-Larry Jones

It's clear I'll never have a career in sports until I learn
to suppress my survival instinct. -- Calvin

John R MacMillan

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
|> This hypothetical "no null pointers in C" crowd would not be moved by
|> the utility of extending the language to allow null pointers. They
|> would consider their existing idioms to be more important than the
|> overall utility and consistency of the language.
|
|Kind of like the "no long long" crowd?

"long long" enhances the consistency of the language?

To paraphrase that old Usenet saw about Nazis, I think threads in
this group have reached their end when someone brings "long long"
into it. :-)
--
To reply by mail, please remove "mail." from my address -- but please
send e-mail or post, not both

Paul Eggert

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

>Null pointers are *already* in C, imperfectly by the way, but zero-sized
>objects aren't;
>it's status quo in one case, innovation in the other.

My argument by analogy wasn't an attempt to disallow null pointers.
(I'm a big fan of null pointers, the more of them the better!)

All I was trying to say is that the `(sizeof(a)/sizeof(a)[0])' argument
is weak -- that's mostly just a problem in the heads of people who
haven't tried size-zero objects.

>It is up to the innovator to "sell" the idea

which is exactly what McIlroy, Ritchie and I were trying to do in this
forum, in our own imperfect ways. We also are trying to sell the idea
by implementing size-zero objects. Implementation experience can be
quite persuasive (at least in some quarters :-).

I can't imagine a C9x implementation _not_ supporting size-zero objects.
What would be the point of disallowing them and angering your users?

Paul Eggert

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Larry Jones <larry...@sdrc.com> writes:

>Paul Eggert wrote:

>> In contrast, the "no size-0 objects" crowd (along with my hypothetical
>> "no null pointers in C" crowd) cannot object on the basis of breaking
>> existing real-world programs. Even if size-0 objects are allowed,
>> the idiom (sizeof(x)/sizeof(*(x))) will continue to work in existing
>> programs.

>Not necessarily -- what if sizeof(*(x)) is also zero?

That wouldn't be possible in an existing program that conforms to the
current standard, as it won't generate size-zero objects.

>> And if a program works in a hypothetical variant of C that
>> does not allow null pointers, then the program will not break simply
>> because the hypothetical standard is changed to allow null pointers.

>Are you serious? They get "broken" in exactly the same way as long long
>"breaks" programs:

> if (*p) { /*...*/ }

>is no longer correct if p might be a null pointer

I was assuming that the program worked in a hypothetical variant of C
that does not allow null pointers. Now, if you extend this
hypothetical variant of C (to add features like casts from 0 to pointer
types, new functions that generate null pointers, etc.) _without_
changing the behavior of previously existing features and functions in
this hypothetical varant, then previously existing programs won't
generate any null pointers, and therefore p can't possibly be null
in them.

Similarly, adding "long long" would not break existing programs if it
were done carefully enough. If it didn't change the behavior of
existing features and functions (e.g. if size_t were still contrained
to be no longer than long), then currently valid code like

printf("%lu", (unsigned long)sizeof x)

would continue to work.

Douglas A. Gwyn

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
Dik T. Winter wrote:
> Talking about empty objects, we just found that on many implementations
> the call
> bsearch(key, NULL, 0, size, compar);
> crashes.
> Is this behaviour allowed?

Yes, undefined behavior includes a possible crash.

Douglas A. Gwyn

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
Paul Eggert wrote:
> ... We also are trying to sell the idea

> by implementing size-zero objects. Implementation experience can be
> quite persuasive (at least in some quarters :-).

I'm sure they can be implemented, although perhaps not without some
issues of conformance.
The issue to be resolved is whether programs that make extensive use of
them run into trouble,
and how much trouble, of what kind.

Larry Jones

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
Paul Eggert wrote:
>
> Larry Jones <larry...@sdrc.com> writes:
>
> >Paul Eggert wrote:
>
> >> Even if size-0 objects are allowed,
> >> the idiom (sizeof(x)/sizeof(*(x))) will continue to work in existing
> >> programs.
>
> >Not necessarily -- what if sizeof(*(x)) is also zero?
>
> That wouldn't be possible in an existing program that conforms to the
> current standard, as it won't generate size-zero objects.

you're right -- I somehow missed the "in existing programs" part. But
note that this has the same kind of problem as long long: although it
doesn't affect existing *programs*, as soon as you modify the program
or try to reuse parts of the code, there are potential problems. My
feeling is that the problems are less serious than those of long long
(and remember, please, that I'm a supporter of both), but I'd expect
the same kinds of objections.

-Larry Jones

Your bangs do a good job of covering up the lobotomy stitches. -- Calvin

Norman Yarvin

unread,
Sep 20, 1998, 3:00:00 AM9/20/98
to
egg...@twinsun.com (Paul Eggert) wrote:

> We also are trying to sell the idea
>by implementing size-zero objects. Implementation experience can be
>quite persuasive (at least in some quarters :-).

This is likely to be a feature that people can use even if you don't
implement it. I have been using zero-size objects in numerical programs
in Fortran 77 for a couple of years, without the slightest problem; and
this in spite of the fact that Fortran is not supposed to have zero-size
objects. I might have had some hesitation to use the feature so
extensively, if I'd known it wasn't supposed to exist, but I only found
that out recently, by trying to explicitly dimension an array size zero,
and having the compiler complain. (The rest of the arrays were
dimensioned size N, where N was passed in and happened to be zero.)

The reason why this worked (and has proven fairly portable) is that it is
difficult to generate code that works for any positive size but does not
work for zero. (It can be done; a too-clever optimizer writer might
decide that since variable N was the size of an array, it by the rules of
the language had to be positive, and might use that assumption to decide
that a certain loop would always be traversed at least once.)

I think the situation for C9X is much the same, though it is a more
powerful language than F77 and thus there are more wrinkles to consider.
In C9X it might be necessary to write a wrapper for malloc in order for
code which uses this undocumented feature to be reasonably portable.


--
Norman Yarvin yar...@cs.yale.edu

Norman Diamond

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
In article <6tv03l$7vp$1...@bird.twinsun.com>, egg...@twinsun.com (Paul Eggert) writes:
>Larry Jones <larry...@sdrc.com> writes:
>>Paul Eggert wrote:
>>>And if a program works in a hypothetical variant of C that
>>>does not allow null pointers, then the program will not break simply
>>>because the hypothetical standard is changed to allow null pointers.

>>Are you serious? They get "broken" in exactly the same way as long long
>>"breaks" programs:
>> if (*p) { /*...*/ }
>>is no longer correct if p might be a null pointer

>I was assuming that the program worked in a hypothetical variant of C
>that does not allow null pointers. Now, if you extend this hypothetical
>variant of C (to add features like casts from 0 to pointer types,
>new functions that generate null pointers, etc.) _without_ changing
>the behavior of previously existing features and functions in this
>hypothetical varant, then previously existing programs won't generate
>any null pointers, and therefore p can't possibly be null in them.

In this hypothetical situation, if null pointers were added badly, they
could break a valid program the same way long long can do. Previously
existing programs might not have generated null pointers because they
handled a signal generated when malloc() failed, but now they abort
when dereferencing a null pointer that malloc returned.

If null pointers hadn't been part of the language before, it would be
destructive to add them to the language without sufficient care.

--
<< If this were the company's opinion, I would not be allowed to post it. >>
"I paid money for this car, I pay taxes for vehicle registration and a driver's
license, so I can drive in any lane I want, and no innocent victim gets to call
the cops just 'cause the lane's not goin' the same direction as me" - J Spammer

John Hauser

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
Larry Jones wrote:
> Dave Hansen wrote:
> > No, but then you've got to fix realloc. Consider
> >
> > p1 = realloc(p2, 0);
> >
> > If p2 == NULL, realloc behaves like malloc, i.e., returns a valid
> > pointer to zero bytes. However, if p2!=NULL, realloc frees the
> > buffer pointed to by p2 and returns NULL.
>
> It's already fixed -- that was never the committee's intent and the
> wording in the most recent draft has been changed to clarify that the
> implementation is free to change the size of the buffer in this case,
> it is not required to free it and return NULL.

Nevertheless, my sources say both Microsoft and the Single UNIX
Specification insist that the buffer is freed and NULL returned.
That's a majority, right there.

- John Hauser

Larry Jones

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to

So? They're both just quoting the C standard. In my experience,
nearly every implementation is consistent in its handling of zero
zero sizes in malloc and realloc: either both return a null pointer,
or neither does.

-Larry Jones

Even though we're both talking english, we're not speaking the same
language.
-- Calvin

John Hauser

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
Larry Jones wrote:
> John Hauser wrote:
> > Larry Jones wrote:
> > > Dave Hansen wrote:
> > > > However, if p2!=NULL, realloc frees the
> > > > buffer pointed to by p2 and returns NULL.
> > >
> > > that was never the committee's intent and the
> > > wording in the most recent draft has been changed to clarify that
> > > the implementation is free to change the size of the buffer in
> > > this case, it is not required to free it and return NULL.
> >
> > Nevertheless, my sources say both Microsoft and the Single UNIX
> > Specification insist that the buffer is freed and NULL returned.
>
> So? They're both just quoting the C standard.

Not necessarily. They may also clarify what happens under
circumstances the C Standard does not define. Microsoft documentation
states explicitly:

The return value is NULL if the size is zero and the buffer
argument is not NULL

This is a promise made that the C committee ought to avoid undermining
cavalierly.

On the other hand, it turns out my source was wrong about the UNIX
standard, which makes me less inclined to argue the issue. Given all
the transgressions Microsoft makes, I don't feel they by themselves
should be allowed to stand in the way of doing ``the right thing.''
So please ignore my previous message.

- John Hauser

Joe Keane

unread,
Sep 25, 1998, 3:00:00 AM9/25/98
to
I think it's interesting, allowing zero dimensions gives a better case
for some sort of `lengthof' operator in the language.

I think people don't like it because, basically, it's not needed, since
the usual macro using `sizeof' and division seems to work fine.

Also a built-in operator would help to prevent stupid mistakes like
"lengthof(char *)", which probably happens fairly often.

--
Joe Keane, amateur mathematician

Clive D.W. Feather

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
In article <6tv0ut$81q$1...@bird.twinsun.com>, Paul Eggert
<egg...@twinsun.com> writes

>I can't imagine a C9x implementation _not_ supporting size-zero objects.
>What would be the point of disallowing them and angering your users?

Because the Standard requires it ?

int x [0];

is a constraint violation.

I don't know any users who rely on zero-sized objects.

--
Clive D.W. Feather | Regulation Officer, LINX | Work: <cl...@linx.org>
Tel: +44 1733 705000 | (on secondment from | Home: <cd...@i.am>
Fax: +44 1733 353929 | Demon Internet) | <http://i.am/davros>
Written on my laptop; please observe the Reply-To address

Clive D.W. Feather

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
In article <6trp2f$1s0$1...@der.twinsun.com>, Paul Eggert
<egg...@twinsun.com> writes

>In contrast, the "no size-0 objects" crowd (along with my hypothetical
>"no null pointers in C" crowd) cannot object on the basis of breaking
>existing real-world programs. Even if size-0 objects are allowed,

>the idiom (sizeof(x)/sizeof(*(x))) will continue to work in existing
>programs.

Not necessarily. For all you know, x is imported from a system header or
has a size dependent on a macro in a system header.

> And if a program works in a hypothetical variant of C that
>does not allow null pointers, then the program will not break simply
>because the hypothetical standard is changed to allow null pointers.

Not if malloc starts returning NULL when it didn't use to.

Douglas A. Gwyn

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to
Clive D.W. Feather wrote:
> I don't know any users who rely on zero-sized objects.

Of course not, since they aren't supported.

Zalman Stern

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to
Clive D.W. Feather (cl...@on-the-train.demon.co.uk) wrote:
: I don't know any users who rely on zero-sized objects.

You probably also don't know many users who consider the bsearch flaw
discussed here as a significant problem. I do. The C community is widely
criticized for not being very interested in tools for writing reliable
software. When I see threads like this, I'm inclined to agree.

-Z-

Douglas A. Gwyn

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to

Nonsense. We like our software to be reliable.
We also like to be able to write systems code in C,
so there have to be "escapes" from any security blanket.

I'm not familiar with any "bsearch flaw";
to what are you referring?

Zalman Stern

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to
Douglas A. Gwyn (gw...@arl.mil) wrote:
: Nonsense. We like our software to be reliable.

: We also like to be able to write systems code in C,
: so there have to be "escapes" from any security blanket.

This is a defense of many things in C. It is not a defense of routines that
gratuitously screwup the end cases. You are spouting party propaganda in
defense of something you probably don't want to defend.

: I'm not familiar with any "bsearch flaw";


: to what are you referring?

If you pass NULL and a zero length to bsearch, you may crash. Another
example is the behavior of strncpy at the boundary case: it does not NUL
terminate the result, hence breaking one of the two simple invariants one
would really like the simple fast C string library to have (given correct
arguments): it doesn't step outside the bounds of string buffers and it
ensures all strings are NUL terminated. (As such, a C string of zero bytes
cannot exist. But we all already knew that...)

Note that there are lots of things one could do to make writing string
manipulation programs in C easier. One of them is the byte bounded sprintf
that is in C9X I believe. Another is a byte bounded varargs strcat that
lets one glue a bunch of strings together into a buffer. It should of
course return the length, -1 if it doesn't fit. It is one thing to advocate
a fixed buffer string library for performance and/or simplicity. It is
quite another to design one that is inordinately difficult to use.

-Z-

Conor O'Neill

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to
In article <zqrZfJK5...@on-the-train.demon.co.uk>, Clive D.W.
Feather <cl...@on-the-train.demon.co.uk> writes

>I don't know any users who rely on zero-sized objects.

I know of many users who'd _like_ to rely on zero-sized objects.

--
Conor O'Neill, Bristol, UK
Speaking for myself, not my Employer

Douglas A. Gwyn

unread,
Oct 3, 1998, 3:00:00 AM10/3/98
to
> : I'm not familiar with any "bsearch flaw";
Zalman Stern wrote:
> If you pass NULL and a zero length to bsearch, you may crash.

Well, sure (although an implementation is free to satisfy
customers like you by doing whatever it is you think should
happen, presumably a no-op). There is a difference between
a null pointer and a valid pointer to a zero-length object
(if such were added to C in a consistent manner).

> Another example is the behavior of strncpy at the boundary case:

> it does not NUL terminate the result, ...


> Note that there are lots of things one could do to make writing string

> manipulation programs in C easier. ...

No doubt the string functions (among many others) could be
improved by redesign. However, we had to standardize the
interfaces that were already in wide use, noty change them.
Early in the C standards process (around 1983 I think)
alternate library functions (with different names!) such as
Whitesmith's were suggested, but existing practice won out.

If a function doesn't do what you want in all cases that
may occur during program execution, don't use it!
It is actually very easy for a competent C programmer to
provide his own versions of such functions, which is very
likely a major factor in minimizing discontent with the
old, standard set of functions.

Francis Glassborow

unread,
Oct 3, 1998, 3:00:00 AM10/3/98
to
In article <3615A320...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>No doubt the string functions (among many others) could be
>improved by redesign. However, we had to standardize the
>interfaces that were already in wide use, noty change them.

Exactly, there are a lot of eccentricities in the Standard Library but
the purpose was to ensure that everyone found the same ones whoever
provided their library. Te users of the day did not want gets() changed
to make it safer at the cost of making it non-portable. At least we can
say to novices 'don't use gets() because it does not protect its buffer
from over-run' Think how much worse it would be if this were on some
machines (because it had not been standardised) and I can just here the
howls about legacy code had the standard required it to have an extra
parameter.

Sometimes idealism must concede to pragmatism. Perfect languages that
no one uses are for academia.

Scott Johnson

unread,
Oct 4, 1998, 3:00:00 AM10/4/98
to
Clive D.W. Feather wrote:
>
> In article <6tv0ut$81q$1...@bird.twinsun.com>, Paul Eggert
> <egg...@twinsun.com> writes

> >I can't imagine a C9x implementation _not_ supporting size-zero objects.
> >What would be the point of disallowing them and angering your users?
>
> Because the Standard requires it ?
>
> int x [0];
>
> is a constraint violation.
>
> I don't know any users who rely on zero-sized objects.


It's a common idiom in GCC, for variable length data structures
which consist of a fixed-size header and zero or more records (all
contiguous in memory, and the number of records can be determined
somehow by examining the header).

Such a structure is defined as follows:


struct bar_record {
/* The record which there may be any number of, blah blah */
};

struct bar_header {
/* Data */
struct bar_record records[0];
};

This provides the following properties, good and/or bad:

* One can easily access the ith record with pHheader->records[i].
Otherwise, one might have to write casts like

((struct bar_record *)(pHeader + 1))[i]

to achieve the same effect.

* sizeof (bar_header) returns the actual size of the header, without
any additional space reserved for one or more records.

* Quite easy to shoot yourself in the foot if you try to reference
more bar_records than there actually are (which is true in any case
when this sort of data structure is used.)

The Linux kernel contains lots of instance of this sort of thing. Gcc
has had this feature (or misfeature, if you prefer) for years; it can be
disabled, of course, with the appropriate flags passed to the compiler.

In my opinion, this sort of thing is more appropriate for lower level
code, where you have to deal with design constraints that might not make
standards bodies happy.

For another possible source of this, imagine a C++ template, (or an
equivalent macro), which looks like this:

template <int i> struct foo {
int a;
int b[i];
};

There are legitimate reasons to have structures like this where
the size of an embedded array is a compile-time parameter. In this
case, having zero instances of b may or may not be useful thing.


Scott

James Russell Kuyper Jr.

unread,
Oct 4, 1998, 3:00:00 AM10/4/98
to
Scott Johnson wrote:
>
> Clive D.W. Feather wrote:
> >
> > In article <6tv0ut$81q$1...@bird.twinsun.com>, Paul Eggert
> > <egg...@twinsun.com> writes
> > >I can't imagine a C9x implementation _not_ supporting size-zero objects.
> > >What would be the point of disallowing them and angering your users?
> >
> > Because the Standard requires it ?
> >
> > int x [0];
> >
> > is a constraint violation.
> >
> > I don't know any users who rely on zero-sized objects.
>
> It's a common idiom in GCC, for variable length data structures
> which consist of a fixed-size header and zero or more records (all
> contiguous in memory, and the number of records can be determined
> somehow by examining the header).
>
> Such a structure is defined as follows:
>
> struct bar_record {
> /* The record which there may be any number of, blah blah */
> };
>
> struct bar_header {
> /* Data */
> struct bar_record records[0];
> };

The proposed C9X standard will support the above idiom, with the small
but significant difference that it uses [] instead of [0]. These are
called 'flexible' arrays. For the sake of maintain compatibility between
the languages, I'd like to suggest that the C9X syntax be supported by
any C++ compilers wishing to support this idiom.

Zalman Stern

unread,
Oct 5, 1998, 3:00:00 AM10/5/98
to
Douglas A. Gwyn (DAG...@null.net) wrote:
: Well, sure (although an implementation is free to satisfy

: customers like you by doing whatever it is you think should
: happen, presumably a no-op).

Lay off the holier than thou "customers like you" rhetoric and stick to the
issue. Ok?

In particular, the specifics of implementations are not interesting. One
cannot rely on bsearch handling a NULL parameter with a zero length depsite
that this is intuitively well defined and can be accomplished in the
implementation with minimal cost. (I'm tempted to say no cost, but I'm sure
someone will challenge that by a cycle or two, which would be missing the
point.) I claim that the vast realm of software we all use would be ever so
slightly more reliable if the standard had decreed that as the way for
bsearch to work. (And yes, some existing implementations would have had to
change. There were lots of things like that in C89 and there are lots
changes forced by C9X.)

(Perhaps one can argue that a bsearch that checks for NULL and fails
improves reliability. If so, feel free to spec it as a guaranteed assertion
failure. I'll go along with that too, but I expect the other alternative is
better.)

Ditto on the string library. It is the way it is and will be so forever. I
am not asking for it to be changed. I am asking for people to realize there
are better designs (even within the spirit of C) and to be honest about the
cost of interfaces that do not handle boundary cases well. I have given two
examples of past mistakes in argument for not making one in the design of a
new feature (variable length arrays).

Part of the problem with the current design and its handling of "zero size
objects" is that once C9X is approved one will likely *never* be able to
fix it. It is likely we will all write a set of wrappers (some rather
onerous as they will encapsulate type definitions and will have to be
macros) to make sure the zero cases are handled cleanly and life will go
on. With more difficulty and more bugs than in an alternative path, but it
will go on even so.

I for one would rather variable length arrays were left out instead.

So what do I propose instead? How about the following:

- One can give zero as the size of a dimension of a variable length
array.
- A new operator is added to do the equivalent of sizeof(A)/sizeof(A[0]).
(Probably an idea of merit in and of itself. This idiom does not
clearly express the intent of getting the number of items in an array.)
- Uniform handling of zero sizes if mandated for malloc and realloc.
This probably has to be that they both return a unique pointer
unless there is no available memory.

-Z-

Zalman Stern

unread,
Oct 5, 1998, 3:00:00 AM10/5/98
to
Francis Glassborow (fra...@robinton.demon.co.uk) wrote:
: Sometimes idealism must concede to pragmatism. Perfect languages that

: no one uses are for academia.

I am offended by this for two reasons. First, your argument is based on
legacy concerns and we are discussing a whole cloth new feature for C.
(Very few implementations have variable length arrays and there is not a
large body of code that depends on them.) Second, you are being
condescending. It is a dismissal of my point as being an overly zelous
pursuit of perfection which cannot be satisfied.

Perhaps yourself and Doug are so caught up in the politics of language
standardization that you no longer have an appreciation for the subtleties
of good language design. Such as, if at all possible, specifying things so
that the boundary cases work.

-Z-

Kees J Bot

unread,
Oct 5, 1998, 3:00:00 AM10/5/98
to
In article <zalmanF0...@netcom.com>,

Zalman Stern <zal...@netcom.com> wrote:
>
>- A new operator is added to do the equivalent of sizeof(A)/sizeof(A[0]).
> (Probably an idea of merit in and of itself. This idiom does not
> clearly express the intent of getting the number of items in an array.)

If we give the phantom element "one beyond the end of the array" not
only an address, but also a size then sizeof(A[0]) can exist for a zero
length array just like &A[0] can exist. The sizeof(A)/sizeof(A[0])
idiom will then work.

Once dynamic arrays are added to the language the average programmer
will make no attempt to avoid zero length arrays. Most compilers will
not check for it, and the generated code will probably work nicely. So
zero length dynamic arrays will be existing practise almost immediately
after dynamic arrays appear in compilers.

C0X will probably specify that zero length (dynamic) arrays are allowed
and that a zero length object need not have a address distinct from any
other object....
--
Kees J. Bot, Systems Programmer, Sciences dept., Vrije Universiteit Amsterdam

Zalman Stern

unread,
Oct 6, 1998, 3:00:00 AM10/6/98
to
Kees J Bot (kjb=731...@cs.vu.nl) wrote:
: In article <zalmanF0...@netcom.com>,

: Zalman Stern <zal...@netcom.com> wrote:
: >
: >- A new operator is added to do the equivalent of sizeof(A)/sizeof(A[0]).
: > (Probably an idea of merit in and of itself. This idiom does not
: > clearly express the intent of getting the number of items in an array.)

: If we give the phantom element "one beyond the end of the array" not
: only an address, but also a size then sizeof(A[0]) can exist for a zero
: length array just like &A[0] can exist. The sizeof(A)/sizeof(A[0])
: idiom will then work.

Pardon me if my reading of the above is missing something, but I believe
the problem is not the evaluation of A[0], but when A[0] is itself a zero
length object and sizeof(A[0]) returns zero. This is nontrivial to resolve,
but it can be done.

-Z-


Clive D.W. Feather

unread,
Oct 6, 1998, 3:00:00 AM10/6/98
to
In article <zalmanF0...@netcom.com>, Zalman Stern
<zal...@netcom.com> writes

>: I'm not familiar with any "bsearch flaw";
>: to what are you referring?
>If you pass NULL and a zero length to bsearch, you may crash.

This is a big deal ?

result = (key == NULL || base == NULL || nmemb == 0 || size == 0 ||
compar == NULL
? NULL : bsearch (key, base, nmemb, size, compar));

>Another
>example is the behavior of strncpy at the boundary case: it does not NUL
>terminate the result,

Known historical practice. Use strncat instead.

Clive D.W. Feather

unread,
Oct 6, 1998, 3:00:00 AM10/6/98
to
In article <zalmanF0...@netcom.com>, Zalman Stern
<zal...@netcom.com> writes
>: Sometimes idealism must concede to pragmatism. Perfect languages that
>: no one uses are for academia.
>I am offended by this for two reasons. First, your argument is based on
>legacy concerns and we are discussing a whole cloth new feature for C.
>(Very few implementations have variable length arrays and there is not a
>large body of code that depends on them.)

Nonetheless this feature interacts with existing features in an
alarmingly large number of ways (see, for example, the rules concerning
how switch interacts with VLAs).

Jerry Coffin

unread,
Oct 6, 1998, 3:00:00 AM10/6/98
to
In article <btmav6...@mega.am.cs.vu.nl>, kjb=731...@cs.vu.nl
says...

[ ... ]

> If we give the phantom element "one beyond the end of the array" not
> only an address, but also a size then sizeof(A[0]) can exist for a zero
> length array just like &A[0] can exist. The sizeof(A)/sizeof(A[0])
> idiom will then work.

You don't need to worry about which address gets specified when you're
passing something to sizeof -- the current standard is quite explicit
in saying that the argument to sizeof is NOT evaluated. It's used
only to figure out a type, and the size of that type becomes the
result of sizeof. Thus, things like:

some_type *x = NULL;

size_t y = sizeof(*x);

is strictly conforming, even though dereferencing a null pointer
clearly gives undefined behavior.

If you're implying that C0x may make this invalid, I certainly hope
you're wrong; changing this will break a HUGE amount of code that's
been legal since long before the current C standard was written. I
can't imagine the committee even considering breaking this, especially
since there's absolutely no reason to do so.

--
Later,
Jerry.

The Universe is a figment of its own imagination.

Zalman Stern

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
Clive D.W. Feather (cl...@on-the-train.demon.co.uk) wrote:
: In article <zalmanF0...@netcom.com>, Zalman Stern
: <zal...@netcom.com> writes
: >: I'm not familiar with any "bsearch flaw";

: >: to what are you referring?
: >If you pass NULL and a zero length to bsearch, you may crash.

: This is a big deal ?

It is when someone (perhaps yourself) writes a piece of code which doesn't
do this and it happens to crash at a time and place far removed from the
action of writing the code...

: result = (key == NULL || base == NULL || nmemb == 0 || size == 0 ||


: compar == NULL
: ? NULL : bsearch (key, base, nmemb, size, compar));

I would not ask for that. I am saying nmemb == 0 should imply that compar
is never called (and henceforth that base is never accessed) so that
passing NULL for base in that case is allowed. This is a good definition
of the function in this case and can be achieved with no cost. (In fact, it
is achieved with no cost in almost all implementations of the function.)

Why am I still wasting my time? Because a number of people seem to think
what happens in the edge cases is either unimportant or can easily be
worked around. I do not raise the bsearch case because I plan to write code
that passes NULL with nmemb == 0, but because it is something one would
expect to work and it will on most implementations. So some people will do
this. I.e. a natural way to write code results in a subtle and rather rare
bug.

The situation with zero length arrays is similar and can be improved.
(bsearch could be fixed as well with a small addition to the standard, but
I'm not asking for that. The string functions cannot really be fixed.)

-Z-

Ross Ridge

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
Zalman Stern <zal...@netcom.com> wrote:
>I am offended by this for two reasons. First, your argument is based on
>legacy concerns and we are discussing a whole cloth new feature for C.

No, it's your argument. You brought bsearch() and strncpy() into this
discussion.

>(Very few implementations have variable length arrays and there is not a

>large body of code that depends on them.) Second, you are being
>condescending. It is a dismissal of my point as being an overly zelous
>pursuit of perfection which cannot be satisfied.

Yah, so?

>Perhaps yourself and Doug are so caught up in the politics of language
>standardization that you no longer have an appreciation for the subtleties
>of good language design. Such as, if at all possible, specifying things so
>that the boundary cases work.

Except that it doesn't, and cannot, make all the boundary cases work.

Ross Ridge


--
l/ // Ross Ridge -- The Great HTMU
[oo][oo] rri...@csclub.uwaterloo.ca
-()-/()/ http://www.csclub.uwaterloo.ca/u/rridge/
db //

Douglas A. Gwyn

unread,
Oct 11, 1998, 3:00:00 AM10/11/98
to
> Zalman Stern <zal...@netcom.com> wrote:
> >Perhaps yourself and Doug are so caught up in the politics of language
> >standardization that you no longer have an appreciation for the subtleties
> >of good language design. Such as, if at all possible, specifying things so
> >that the boundary cases work.

As zero-sized object POC, obviously I *am* concerned with making
boundary cases work.
Sometimes, this can't be done because previous specs have already broken
the boundary cases and code may depend on those specs.
For bsearch/qsort, you can allocate a 0-length array and if the
allocation succeeded you can feed its base address to these functions.
It is simply an error to feed them a null pointer where an array
reference is required.

Nick Maclaren

unread,
Oct 12, 1998, 3:00:00 AM10/12/98
to

Basically, there are two consistent approaches:

1) To make zero-sized objects first-class, and ensure that all
operations are defined appropriately, so that they can be used like
any others.

2) To exclude zero-sized objects, and to ensure that they are
forbidden in all cases, and diagnosed in all relevant ones. NULL
pointers are something different.

The choice is more religious than technical - both models have been
used to produce consistent language definitions. I am an agnostic.

Frankly, I think that the mistake was not taking a clear decision
to go one way or the other, but in defining each language aspect
more or less independently. C89 was a bit of a mess, but I don't
think that C9X is any worse - it may even be a bit better.


Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Email: nm...@cam.ac.uk
Tel.: +44 1223 334761 Fax: +44 1223 334679

0 new messages