Topic: are zero lengthed arrays allowed?
Author: clive@stdc.demon.co.uk (Clive D.W. Feather)
Date: 1995/08/06 Raw View
In article <DCIIHw.97u@agora.rdrop.com>,
David Cary <cary@agora.rdrop.com> wrote:
> Doesn't a ANSI-compliant compiler have the right to reshuffle a structure ?
In a word: no.
[In ISO Standard C, anyway; I say nothing about C++.]
--
Clive D.W. Feather | If you lie to the compiler,
clive@demon.net (work, preferred) | it will get its revenge.
clive@stdc.demon.co.uk (home) | - Henry Spencer
Author: jimad@microsoft.com (jimad)
Date: 1995/08/03 Raw View
In C++ zero lengthed arrays are perfectly reasonable and sensible things.
C++ supports dynamically allocated zero-lengthed arrays, but
not statically allocated zero-lengthed arrays. In the context
of templated classes this makes little sense, IMHO. Consider
a templated class using a default buffer, that can be dynamically
grown. The size of the default buffer is a template parameter.
Zero is a perfectly reasonable size. When the zero length default buffer
is filled, then it is dynamically grown.
The one-past the end pointer makes perfect sense here. Let's
say in the above templated case an end of buffer ptr is kept
to signal buffer full. In the zero-length buffer case the
one-past the end ptr becomes identical to the head of buffer
ptr, buffer full condition is signaled immediately, a larger
dynamically allocated buffer is allocated, and every thing
works perfectly.
Assuming zero length statically allocated buffers were allowed.
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/07/30 Raw View
scjones@thor.sdrc.com (Larry Jones) writes:
>ffarance@aol.com (FFarance) writes:
>> [...] However, there has been a revival of
>> interest on zero-length objects. Doug Gwyn has been leading the
>> charge. I think he will be proposing them for C9X.
>
>My recollection is different -- I remember the key sticking point being
>that the standard was heavily dependent on the concept of "object" but,
>if you allow objects to have a size of zero, the definition of "object"
>falls apart.
Why does it fall apart?
>Assuming we could fix that (though I don't recall anyone
>having a concrete suggestion for doing so), we would then have to have
>different terms for "real objects" and "zero-size objects" because they
>have different behaviors in some cases.
I'm not yet convinced that this is really the case; it seems to me
that if there is a difference in behaviours, it is much smaller than
you suggest.
>For example, a zero-size
>object is presumably an lvalue (so you can take it's address), but it's
>never a modifiable lvalue (reguardless of its type)
Why not?
What's wrong with
struct Empty {} empty1, empty2;
void foo() {
empty1 = empty2;
}
? GNU C allows this. I don't see a problem.
>and it has no value
Again, why not?
An object with size zero should have a singleton set of possible values.
That is, there should be exactly one value of type `struct Empty'
or of type `void'.
>(it behaves more like a void expression than an expression of its type).
IMHO, the way `void' is used in ANSI C is very confusing.
Perhaps if the ANSI C committee had known a bit more set theory,
they'd have got it right ;-)
A void expression ought to have a value too.
The following should be legal:
void x;
(Incidentally, gcc allows this, but I suspect it is a bug - there
is no warning even with -ansi -pedantic.)
The following should also be legal:
void y = (void) 42;
So should the following:
void foo();
void bar() {
return foo();
}
void baz() {
return (void) 42;
}
In other words, I think the `void' type (as used in void expressions, e.g.
casts to void and functions with void return values) ought to have been like
the unit type in SML.
>I would note that, despite the committee's insistence on not having zero
>size objects, the current standard does have exactly one case where
>these occur (although it doesn't acknowledge it) -- the "thingy" just
>past the end of an array that you're allowed to point to but not
>reference behaves, as far as I can tell, exactly like a zero-size
>object.
I think that is a categorically different case.
--
Fergus Henderson | Designing grand concepts is fun;
fjh@cs.mu.oz.au | finding nitty little bugs is just work.
http://www.cs.mu.oz.au/~fjh | -- Brooks, in "The Mythical Man-Month".
PGP key fingerprint: 00 D7 A2 27 65 09 B6 AC 8B 3E 0F 01 E7 5D C4 3F
Author: cary@agora.rdrop.com (David Cary)
Date: 1995/07/30 Raw View
There are other ways of implementing variable-arity graphs that may be easier
to debug (and make compiler happier).
The classic way is to map a variable-arity tree onto a binary tree:
struct node{
int arity;
struct node *oldest_child;
struct node *next_youngest_sibling;
};
struct node *px;
int n;
...
px=(struct node *)malloc(sizeof(struct node));
px->arity=n;
(the arity part of the node is technically redundant ... but it's
possible that keeping that information in 2 different places may speed up
some code).
I just thought you might like another alternative that perhaps you hadn't
considered before.
(I'm positive this works with *trees*; if it doesn't work with graphs,
would you mind telling me ?)
The trick Juliusz uses is pretty clever. But...
Doesn't a ANSI-compliant compiler have the right to reshuffle a structure ?
I don't know of any compilers that change the order of a structure (which
would make his program crash horribly).
I do know of compilers that change the structure in other ways. In
particular, sizeof(node) depends on the exact compiler and the exact
options used.
PS: my mail to Juliusz Chroboczek bounced
550 <jch@dm.unibo.it.jos>... Host unknown (Name server: dm.unibo.it.jos:
host not found)
In article <3sum24$9he@solutions.solon.com> jos@and.nl (Jos A. Horsmeier)
wrote:
: In article <3spcvj$9ce@solutions.solon.com>, jch@dm.unibo.it (Juliusz
: Chroboczek) wrote:
...
: | Suppose I want to implement a structure containing an array whose
: |size depends on the value of another field (my application has graphs
: |with variable arity nodes). Something like:
: |
: |in K&R C, I would simply write:
: |
: |: struct node{
: |: int arity;
: |: struct node *ports[0];
: |: };
: |:
: |: struct node *x;
: |: int n;
: |: ...
: |: x=malloc(sizeof(struct node)+n*sizeof(struct node *));
: |: x->arity=n;
: |
: | I've been quite surprised, lately, to find that the previous
: |allocation is illegal in ANSI C! The standard makes me declare the
: |fiels as:
: |
: |: struct node *ports[1];
: |
: |so that then I have to substract 1 from the second term each time I
: |allocate!
: |
: | Could anyone explain me the rationale of that seemingly absurd
: |decision? Or, if the previous method is utterly illegal in ANSI C
: |(using structures larger than declared), what is the right one?
--
David Cary
d.cary@ieee.org for email. type "finger cary@agora.rdrop.com" for more info.
Author: msb@sq.sq.com (Mark Brader)
Date: 1995/07/27 Raw View
Frank Farance (ffarance@aol.com):
> > > ... but, this isn't ISO C. It should be rewritten as:
> > >
> > > struct
> > > {
> > > int length;
> > > char contents[1];
> > > };
Me, Mark Brader:
> > Er, Frank, assuming that this structure is to be used in the "obvious"
> > way, the committee has ruled that you can't do that in ISO C. ...
Frank:
> Yes, you're right about defect report 51. ... In
> the response, the correct way of writing this should be:
>
> struct x
> {
> int length;
> char contents[LARGE_NUM];
> };
> struct x *p;
>
> /* allocates structure with 100-byte contents */
> p = malloc(sizeof(struct x)-LARGE_NUM+100);
But the draft response to DR 073 (currently up for balloting) prohibits
this also. You can do the malloc, of course, but you can't refer to
p->contents[0]
because that's equivalent to
(*p).contents[0]
and *p ought to denote a *whole* struct x, and the draft DR response says:
* The dot selection operator is at liberty to require the complete
* structure denoted by its left hand side to be accessed. Such an
* access would result in undefined behavior.
(The actual code in the DR is somewhat different, but the quoted text
is wholly relevant.)
> The response to DR51 says that the idiom, i.e., "contents[1]", while
> common is not strictly conforming. The reason why is because the
> pointer arithmetic may change as the size of the structure increases.
> For example, on Intel architectures, the following might use different
> pointer arithmetic:
>
> struct could_use_near_or_huge_pointer
> {
> int length;
> char contents[60000];
> };
>
> struct must_use_huge_pointer
> {
> int length;
> char contents[70000];
> };
That's a motivation for *wanting* the standard to prohibit the first
construct (the "struct hack"), but not a justification for ruling that
the present standard *does* prohibit it. There is also a motivation
in the other direction, i.e. the body of existing code that uses the
struct hack. The issue of whether it should or not is reminiscent of
the pre-standard days when certain pointer equality comparisons might
not compare the whole pointer on some machines -- the standard chose to
prohibit that optimization. I contend that it also (unfortunately,
indirectly) prohibits the optimization Frank describes, making the
response to DR 51 wrong; but I'll shut up about that now, for now.
There is, however, always this way:
struct x
{
int length;
char *contents;
};
struct x *p;
char *cp;
p = cp = malloc ...;
p->contents = cp + sizeof *p;
But it becomes trickier if the type of the contents is not a character
type, because alignment becomes a consideration.
--
Mark Brader "One might as well complain about the Sun
msb@sq.com rising in the daytime instead of at night,
SoftQuad Inc., Toronto when we need it more." -- John Lawler
This article is in the public domain.
Author: David Raine <raine@ferndown.ate.slb.com>
Date: 1995/07/27 Raw View
msb@sq.sq.com (Mark Brader) wrote:
>Frank Farance (ffarance@aol.com) writes:
>> ... but, this isn't ISO C. It should be rewritten as:
>>
>> struct
>> {
>> int length;
>> char contents[1];
>> };
>
>Er, Frank, assuming that this structure is to be used in the "obvious"
>way, the committee has ruled that you can't do that in ISO C. Defect
>Report 51, you know. (I continue to disagree strongly with the ruling,
>but a DR objecting to it that I worked on seems to have fallen victim
>to red tape.)
Could you be more specific about DR 51? Why can't you do this in ISO?
David.
Author: ffarance@aol.com (FFarance)
Date: 1995/07/27 Raw View
> From: msb@sq.sq.com (Mark Brader)
>
> Frank Farance (ffarance@aol.com) writes:
> > ... but, this isn't ISO C. It should be rewritten as:
> >
> > struct
> > {
> > int length;
> > char contents[1];
> > };
>
> Er, Frank, assuming that this structure is to be used in the "obvious"
> way, the committee has ruled that you can't do that in ISO C. Defect
> Report 51, you know. (I continue to disagree strongly with the ruling,
> but a DR objecting to it that I worked on seems to have fallen victim
> to red tape.)
Yes, you're right about defect report 51. After scratching my head
for a while, I remembered why the response to DR51 makes sense. In
the response, the correct way of writing this should be:
struct x
{
int length;
char contents[LARGE_NUM];
};
struct x *p;
/* allocates structure with 100-byte contents */
p = malloc(sizeof(struct x)-LARGE_NUM+100);
The response to DR51 says that them idiom, i.e., "contents[1]", while
common is not strictly conforming. The reason why is because the
pointer arithmetic may change as the size of the structure increases.
For example, on Intel architectures, the following might use different
pointer arithmetic:
struct could_use_near_or_huge_pointer
{
int length;
char contents[60000];
};
struct must_use_huge_pointer
{
int length;
char contents[70000];
}
If you use the second one, you would always get the pointer arithmetic
right, when you allocated smaller structures.
I had forgotten about DR51 in my original posting. Thanx for pointing
out my mistake.
-FF
-------------------------------------------------------------------
(``I only use AOL for reading netnews.'')
Frank Farance, Farance Inc.
E-mail: frank@farance.com, Telephone: +1 212 486 4700
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor
Author: scjones@thor.sdrc.com (Larry Jones)
Date: 1995/07/27 Raw View
In article <3ur7gi$huu@newsbf02.news.aol.com>, ffarance@aol.com (FFarance) writes:
> I remember the vote in X3J11 many years ago on whether we should support
> zero-length objects. Those that have mathematical backgrounds (like
> myself) felt that this was very important for code simiplicity -- the
> same way the number zero is a useful concept. I think the reason
> we lost (my memory is fuzzy on this) was that (1) there were varying
> implementations of "malloc" (some returned a null-pointer, others
> returned a pointer to a zero-length object), (2) some linkers didn't
> support zero-length objects. However, there has been a revival of
> interest on zero-length objects. Doug Gwyn has been leading the
> charge. I think he will be proposing them for C9X.
My recollection is different -- I remember the key sticking point being
that the standard was heavily dependent on the concept of "object" but,
if you allow objects to have a size of zero, the definition of "object"
falls apart. Assuming we could fix that (though I don't recall anyone
having a concrete suggestion for doing so), we would then have to have
different terms for "real objects" and "zero-size objects" because they
have different behaviors in some cases. For example, a zero-size
object is presumably an lvalue (so you can take it's address), but it's
never a modifiable lvalue (reguardless of its type) and it has no value
(it behaves more like a void expression than an expression of its type).
I would note that, despite the committee's insistence on not having zero
size objects, the current standard does have exactly one case where
these occur (although it doesn't acknowledge it) -- the "thingy" just
past the end of an array that you're allowed to point to but not
reference behaves, as far as I can tell, exactly like a zero-size
object.
----
Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH 45150-2789 513-576-2070
larry.jones@sdrc.com
Mom must've put my cape in the wrong drawer. -- Calvin
Author: ffarance@aol.com (FFarance)
Date: 1995/07/27 Raw View
> From: tanmoy@qcd.lanl.gov (Tanmoy Bhattacharya)
>
> In article <3v6f7k$o6l@newsbf02.news.aol.com>, ffarance@aol.com
(FFarance)
> writes:
> ...
> |> For example, on Intel architectures, the following might use
different
> |> pointer arithmetic:
> |>
> |> struct could_use_near_or_huge_pointer
> |> {
> |> int length;
> |> char contents[60000];
> |> };
> |>
> |> struct must_use_huge_pointer
> |> {
> |> int length;
> |> char contents[70000];
> |> }
> |>
> |> If you use the second one, you would always get the pointer
arithmetic
> |> right, when you allocated smaller structures.
>
> Why is this true? Does the standard specify that the alignment
requirement of
> the struct could_use_near_or_huge_pointer must be at least as strict as
> that of struct must_use_huge_pointer? (i.e. is it non-conformant for an
> implementation to demand the latter struct to aligned at a segment
boundary
> with more padding between the first two fields, whereas the former is
just
> word aligned with no padding?) If not, is the smaller malloc required
> to be properly aligned for the larger type as well? (In the extreme
case, is
> malloc(1) required to be properly aligned at a segment boundary on
unlucky
> implementations?)
The C Standard doesn't specify anything about stricter alignment,
but is does say something about the use of a pointer returned
from "malloc":
Subclause 7.10.3, Memory management functions
... The pointer returned if the allocation succeeds
is suitably aligned so that it may be assigned to a
pointer to any type of object and then used to access
such an object or an array of such objects in the space
allocated (until the space is explicity freed or
reallocated).
So alignment wouldn't be an issue with respect to the storage allocated.
However, as you point out, it is possible to have different, possibly
non-existent, holes between "length" and "contents". David Keaton pointed
out that on some architectures, the alignment varies according to the
length of "contents":
sizeof(contents)==1 --> alignment 1
sizeof(contents)==2 --> alignment 2
sizeof(contents)==4 --> alignment 4
sizeof(contents)==8 --> alignment 8
sizeof(contents)>8 --> alignment 8
It seems a ``safe'' bet that after a certain size (say, the size of
the machine word), the alignment stays the same. This is why DR51
suggested a length of 10000 (according to David). David also pointed
out that in strictly conforming programs (in contrast to conforming
programs), objects have a maximum size of 32767 bytes, so the size
of "contents" plus the remainder of the structure should be less
than 32767 bytes.
> Could someone please explain clearly how and in what
> form the standard allows the `struct hack'?
The defect report (which I summarized in the previous posting)
explains how this is possible. If your question is why this is
useful, one possible use might be "contents" represents a
variable length string. Another use is certain styles of
``object-oriented'' programming.
This DR probably needs revisiting at the 1995-10 meeting. Thanx for
your insight.
-FF
-------------------------------------------------------------------
(``I only use AOL for reading netnews.'')
Frank Farance, Farance Inc.
E-mail: frank@farance.com, Telephone: +1 212 486 4700
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor
Author: dmm@neutron.torolab.ibm.com (Dave Mooney)
Date: 1995/07/27 Raw View
Larry Jones <scjones@thor.sdrc.com> wrote:
> I would note that, despite the committee's insistence on not having zero
> size objects, the current standard does have exactly one case where
> these occur (although it doesn't acknowledge it) -- the "thingy" just
> past the end of an array that you're allowed to point to but not
> reference behaves, as far as I can tell, exactly like a zero-size
> object.
There's also the thing that you get back from malloc(0) under
implementations that choose to return a unique pointer rather than NULL.
And the thingy that you reference with fread(ptr, 0, nmemb, stream).
dave
--
Dave Mooney | IBM Toronto Lab | "We see the fish below the ice sometimes."
Author: msb@sq.sq.com (Mark Brader)
Date: 1995/07/28 Raw View
>>> struct
>>> {
>>> int length;
>>> char contents[1];
>>> };
>>
>> ... assuming that this structure is to be used in the "obvious"
>> way, the committee has ruled that you can't do that in ISO C. Defect
>> Report 51, you know. ...
> Could you be more specific about DR 51? Why can't you do this in ISO?
If you declare a simple array object, e.g. "int x[5]", then undefined
behavior occurs (which is what I meant by "you can't do that") if
you derive a pointer from x and do pointer arithmetic generating an
offset which takes it outside the array. (As an exception, you are
allowed to generate a pointer one place past the last element, if you
don't attempt to dereference that pointer value.)
In the "struct hack" situation under discussion, you are trying to use
an expression like p->contents[4], where p was obtained by malloc()ing
a suitably large object. Now the element that you're trying to access,
and the one that you're trying to derive a pointer to it from (i.e.
p->contents[0]) are *not* both part of the declared array p->contents,
but they *are* both part of another object, the one that you got from
malloc(). So the issue is, which object determines how far you can
index off the pointer?
The DR response states in effect that the determination is based on the
object *that you derived the pointer from*. Thus, using p->contents
in the expression legitimizes a prohibition on indexing the resulting
pointer by [4]. If you derive a pointer to the element p->contents[0]
some *other* way, i.e. directly from the return value of malloc(), then
*that* pointer can be indexed safely by [4].
(The draft response to DR 072 question (d), currently being balloted,
apparently asserts that my previous sentence is wrong. I can't imagine
what the person who wrote it was thinking of; it merely cites the
DR 051 response, which doesn't seem to apply to the code in question.)
--
Mark Brader "Hacking for 8 years gives a guy a memory.
msb@sq.com If you was with a woman -- I'd've noticed."
SoftQuad Inc., Toronto PHANTOM LADY
This article is in the public domain.
Author: jfw@proteon.com (John Woods)
Date: 1995/07/28 Raw View
dmm@neutron.torolab.ibm.com (Dave Mooney) writes:
>There's also the thing that you get back from malloc(0) under
>implementations that choose to return a unique pointer rather than NULL.
That's not an object of 0 size, that's an object whose size is not guaranteed
to be as much as 1. You can't write a program that depends on its size,
nor even determine its size.
>And the thingy that you reference with fread(ptr, 0, nmemb, stream).
Since there are no C objects of zero size, I think that's a case of lying
to the library (which may or may not entitle the compiler to extract revenge);
in this case, you aren't referencing an object of 0 size, you're referring to
0 bytes of an object of nonzero size (several times, perhaps).
Author: msb@sq.sq.com (Mark Brader)
Date: 1995/07/26 Raw View
Frank Farance (ffarance@aol.com) writes:
> ... but, this isn't ISO C. It should be rewritten as:
>
> struct
> {
> int length;
> char contents[1];
> };
Er, Frank, assuming that this structure is to be used in the "obvious"
way, the committee has ruled that you can't do that in ISO C. Defect
Report 51, you know. (I continue to disagree strongly with the ruling,
but a DR objecting to it that I worked on seems to have fallen victim
to red tape.)
--
Mark Brader "How can we believe that?"
msb@sq.com "Because this time it's true!"
SoftQuad Inc., Toronto -- Lynn & Jay: YES, PRIME MINISTER
This article is in the public domain.
Author: ffarance@aol.com (FFarance)
Date: 1995/07/26 Raw View
> From: msb@sq.sq.com (Mark Brader)
>
> Frank Farance (ffarance@aol.com) writes:
> > ... but, this isn't ISO C. It should be rewritten as:
> >
> > struct
> > {
> > int length;
> > char contents[1];
> > };
>
> Er, Frank, assuming that this structure is to be used in the "obvious"
> way, the committee has ruled that you can't do that in ISO C. Defect
> Report 51, you know. (I continue to disagree strongly with the ruling,
> but a DR objecting to it that I worked on seems to have fallen victim
> to red tape.)
Yes, you're right about defect report 51. After scratching my head
for a while, I remembered why the response to DR51 makes sense. In
the response, the correct way of writing this should be:
struct x
{
int length;
char contents[LARGE_NUM];
};
struct x *p;
/* allocates structure with 100-byte contents */
p = malloc(sizeof(struct x)-LARGE_NUM+100);
The response to DR51 says that the idiom, i.e., "contents[1]", while
common is not strictly conforming. The reason why is because the
pointer arithmetic may change as the size of the structure increases.
For example, on Intel architectures, the following might use different
pointer arithmetic:
struct could_use_near_or_huge_pointer
{
int length;
char contents[60000];
};
struct must_use_huge_pointer
{
int length;
char contents[70000];
}
If you use the second one, you would always get the pointer arithmetic
right, when you allocated smaller structures.
I had forgotten about DR51 in my original posting. Thanx for pointing
out my mistake.
-FF
-------------------------------------------------------------------
(``I only use AOL for reading netnews.'')
Frank Farance, Farance Inc.
E-mail: frank@farance.com, Telephone: +1 212 486 4700
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor
Author: tanmoy@qcd.lanl.gov (Tanmoy Bhattacharya)
Date: 1995/07/26 Raw View
In article <3v6f7k$o6l@newsbf02.news.aol.com>, ffarance@aol.com (FFarance)
writes:
<snip>
|> Yes, you're right about defect report 51. After scratching my head
|> for a while, I remembered why the response to DR51 makes sense. In
|> the response, the correct way of writing this should be:
|>
|> struct x
|> {
|> int length;
|> char contents[LARGE_NUM];
|> };
|> struct x *p;
|>
|> /* allocates structure with 100-byte contents */
|> p = malloc(sizeof(struct x)-LARGE_NUM+100);
|>
|> The response to DR51 says that the idiom, i.e., "contents[1]", while
|> common is not strictly conforming. The reason why is because the
|> pointer arithmetic may change as the size of the structure increases.
|> For example, on Intel architectures, the following might use different
|> pointer arithmetic:
|>
|> struct could_use_near_or_huge_pointer
|> {
|> int length;
|> char contents[60000];
|> };
|>
|> struct must_use_huge_pointer
|> {
|> int length;
|> char contents[70000];
|> }
|>
|> If you use the second one, you would always get the pointer arithmetic
|> right, when you allocated smaller structures.
Why is this true? Does the standard specify that the alignment requirement of
the struct could_use_near_or_huge_pointer must be at least as strict as
that of struct must_use_huge_pointer? (i.e. is it non-conformant for an
implementation to demand the latter struct to aligned at a segment boundary
with more padding between the first two fields, whereas the former is just
word aligned with no padding?) If not, is the smaller malloc required
to be properly aligned for the larger type as well? (In the extreme case, is
malloc(1) required to be properly aligned at a segment boundary on unlucky
implementations?) Could someone please explain clearly how and in what
form the standard allows the `struct hack'?
On a slightly different topic, I heard in this news group that there was a DR
which stated that one could access a part of an object, even if the whole
object did not exist. (Something like, though not precisely, what you are
trying to do.) I did not see the original statement, and could have been
hallucinating for all I know: any help about what the exact statement was?
Cheers
Tanmoy
--
tanmoy@qcd.lanl.gov(128.165.23.46) DECNET: BETA::"tanmoy@lanl.gov"(1.218=1242)
Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87544-0285,USA H:#3,802,9 St,NM87545
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003 voice: 1 (505) 665 4733 [ Home: 1 (505) 662 5596 ]
Author: ffarance@aol.com (FFarance)
Date: 1995/07/26 Raw View
> From: msb@sq.sq.com (Mark Brader)
>
> Frank Farance (ffarance@aol.com) writes:
> > ... but, this isn't ISO C. It should be rewritten as:
> >
> > struct
> > {
> > int length;
> > char contents[1];
> > };
>
> Er, Frank, assuming that this structure is to be used in the "obvious"
> way, the committee has ruled that you can't do that in ISO C. Defect
> Report 51, you know. (I continue to disagree strongly with the ruling,
> but a DR objecting to it that I worked on seems to have fallen victim
> to red tape.)
Yes, you're right about defect report 51. After scratching my head
for a while, I remembered why the response to DR51 makes sense. In
the response, the correct way of writing this should be:
struct x
{
int length;
char contents[LARGE_NUM];
};
struct x *p;
/* allocates structure with 100-byte contents */
p = malloc(sizeof(struct x)-LARGE_NUM+100);
The response to DR51 says that them idiom, i.e., "contents[1]", while
common is not strictly conforming. The reason why is because the
pointer arithmetic may change as the size of the structure increases.
For example, on Intel architectures, the following might use different
pointer arithmetic:
struct could_use_near_or_huge_pointer
{
int length;
char contents[60000];
};
struct must_use_huge_pointer
{
int length;
char contents[70000];
}
If you use the second one, you would always get the pointer arithmetic
right, when you allocated smaller structures.
I had forgotten about DR51 in my original posting. Thanx for pointing
out my mistake.
-FF
-------------------------------------------------------------------
(``I only use AOL for reading netnews.'')
Frank Farance, Farance Inc.
E-mail: frank@farance.com, Telephone: +1 212 486 4700
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor
Author: ffarance@aol.com (FFarance)
Date: 1995/07/22 Raw View
Zero-length arrays, structures, or objects aren't allowed in C.
Many compilers allow:
struct
{
int length;
char contents[0];
};
but, this isn't ISO C. It should be rewritten as:
struct
{
int length;
char contents[1];
};
Similarly, you can't "malloc" an object of zero bytes in ISO C. Many
libraries support this, but it isn't ISO C.
I remember the vote in X3J11 many years ago on whether we should support
zero-length objects. Those that have mathematical backgrounds (like
myself) felt that this was very important for code simiplicity -- the
same way the number zero is a useful concept. I think the reason
we lost (my memory is fuzzy on this) was that (1) there were varying
implementations of "malloc" (some returned a null-pointer, others
returned a pointer to a zero-length object), (2) some linkers didn't
support zero-length objects. However, there has been a revival of
interest on zero-length objects. Doug Gwyn has been leading the
charge. I think he will be proposing them for C9X.
-FF
-------------------------------------------------------------------
(``I only use AOL for reading netnews.'')
Frank Farance, Farance Inc.
E-mail: frank@farance.com, Telephone: +1 212 486 4700
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor
Author: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 1995/07/24 Raw View
In article <3uo582$8of@snlsu1> devitto@london.sinet.slb.com (Dom De
Vitto) writes:
|> gcc premits zero length arrays (without -pedantic) giving this
|> sort of example:
|> struct line {
|> int length;
|> char contents[0];
|> };
|> /* ... */
|> {
|> struct line* thisline = (struct line*) malloc(sizeof(struct line)
|> + this_length)
|> this_line->length = this_length;
|> }
|> This circumvents having to either give 'contents' a length of 1
|> or having a pointer member - which both waist memory.
The problem is, that the obvious ways of accessing the memory
following the 0 length array are not legal (undefined behavior). This
has been discussed many times, and was even the object of a defect
report in the C standard (unless my memory is playing tricks on me).
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: devitto@london.sinet.slb.com (Dom De Vitto)
Date: 1995/07/21 Raw View
gcc premits zero length arrays (without -pedantic) giving this
sort of example:
struct line {
int length;
char contents[0];
};
/* ... */
{
struct line* thisline = (struct line*) malloc(sizeof(struct line)
+ this_length)
this_line->length = this_length;
}
This circumvents having to either give 'contents' a length of 1
or having a pointer member - which both waist memory.
Dom
Author: ring@porky.cb.att.com (WarrenRing)
Date: 1995/07/20 Raw View
>> To expand on this, since empty structs are allowed (at least in C++),
>> and have a sizeof 1, why would putting a zero-length array into an
>> otherwise empty struct make it smaller? I assume that empty structs
>> are allowed in C as well. Just out of curiosity, can anyone confirm
>> or deny?
>
>I deny.
>
>Empty structures are not permitted in Standard C.
>
What about:
char xxx[0], yyy[22];
Since xxx has no length, the address of xxx is meaningless. Since
many compilers store variables in succeeding addresses as they're
defined, it's possible that xxx will be assigned the same address as
yyy, if the compiler accepts the statement in the first place.
Warren Ring
ring@cbsms1.cb.att.com
Author: halasz@caip.rutgers.edu
Date: 1995/07/20 Raw View
In article <DC0oE1.9EE@nntpa.cb.att.com>, ring@porky.cb.att.com (WarrenRing) writes
> What about:
>
> char xxx[0], yyy[22];
>
> Since xxx has no length, the address of xxx is meaningless.
Wrong: it has a length, that length is 0.
The address is meaningful, as the valu stord in a 'void *' is meaningful.
> Since many compilers store variables in succeeding addresses as they're
> defined, it's possible that xxx will be assigned the same address as
> yyy, if the compiler accepts the statement in the first place.
That befell me with a linker: it claimd that it loaded a datum, but it onlie
assignd the datum an address, and load the followind datum at the same address,
as if the first one s length were 0 (it was not).
Author: axl@zedat.fu-berlin.de (Axel)
Date: 1995/07/20 Raw View
In article <DC0oE1.9EE@nntpa.cb.att.com>, ring@porky.cb.att.com says...
>
>>> To expand on this, since empty structs are allowed (at least in C++),
>>> and have a sizeof 1, why would putting a zero-length array into an
>>> otherwise empty struct make it smaller? I assume that empty structs
>>> are allowed in C as well. Just out of curiosity, can anyone confirm
>>> or deny?
>>
>>I deny.
>>
>>Empty structures are not permitted in Standard C.
>>
>
>What about:
>
> char xxx[0], yyy[22];
>
>Since xxx has no length, the address of xxx is meaningless. Since
>many compilers store variables in succeeding addresses as they're
>defined, it's possible that xxx will be assigned the same address as
>yyy, if the compiler accepts the statement in the first place.
>
>Warren Ring
>ring@cbsms1.cb.att.com
>
The workarround would be to assign these empty array the nil pointer, or
even better to make the compiler see the declaration and ignore the variable
xxx, when an attempt to use this var is made the compiler could get an error
produced.
Axel Thimm
Author: jsa@edg.com (J. Stephen Adamczyk)
Date: 1995/07/20 Raw View
In article <DC0oE1.9EE@nntpa.cb.att.com>, ring@porky.cb.att.com says...
>>> To expand on this, since empty structs are allowed (at least in C++),
>>> and have a sizeof 1, why would putting a zero-length array into an
>>> otherwise empty struct make it smaller? I assume that empty structs
>>> are allowed in C as well. Just out of curiosity, can anyone confirm
>>> or deny?
>>
>>I deny.
>>
>>Empty structures are not permitted in Standard C.
>>
>What about:
>
> char xxx[0], yyy[22];
>
>Since xxx has no length, the address of xxx is meaningless. Since
>many compilers store variables in succeeding addresses as they're
>defined, it's possible that xxx will be assigned the same address as
>yyy, if the compiler accepts the statement in the first place.
>
>Warren Ring
>ring@cbsms1.cb.att.com
Empty arrays aren't allowed in C; the declaration above is not valid.
Syntactically empty structs are not allowed in C. More precisely,
struct A { };
is clearly invalid -- the syntax doesn't allow it. Some other cases
that might be zero-sized have undefined behavior:
struct B { int : 0; };
Steve Adamczyk
Edison Design Group
Author: clive@stdc.demon.co.uk (Clive D.W. Feather)
Date: 1995/06/21 Raw View
In article <3s7jpd$a2g@cmcl2.NYU.EDU>, Ed Osinski <osinski@cs.nyu.edu> wrote:
> To expand on this, since empty structs are allowed (at least in C++),
> and have a sizeof 1, why would putting a zero-length array into an
> otherwise empty struct make it smaller? I assume that empty structs
> are allowed in C as well. Just out of curiosity, can anyone confirm
> or deny?
I deny.
Empty structures are not permitted in Standard C.
--
Clive D.W. Feather | If you lie to the compiler,
clive@demon.net (work, preferred) | it will get its revenge.
clive@stdc.demon.co.uk (home) | - Henry Spencer
Author: "uwe.tantz" <c4037>
Date: 1995/06/19 Raw View
On 19 Jun 1995, Timothy E. Hoff wrote:
>
> I have followed some of the discussion about empty arrays in C so I
> don't think that I am repeating anyone.
>
> In C, arrays are defined statically at compile time. Therefore, it seems
> reasonable for a compiler to refuse to compile something which must always
> be unusable (because the name of any array is its const address).
>
> I hope this helps clarify the original question.
>
zero-lengthed arrays are often used in windows-api (although I think
it is dirty C(--) manner)
They are reasonable if you cast a memory block to a struct, the last element
of which is a zero lengthed array.
Look at this (for example):
struct TBitmap
{
long NumberOfBytes;
char Bitmap[0];
};
void DisplayBitmap (int Id)
{
char* Buffer = LoadResource (Id);
TBitmap* Picture = (TBitmap*) Buffer;
DoSomething (Picture);
}
Of course this may lead to problems if you want to copy the struct, but
I have seen constructs like this not just once.
Uwe
+---------------------+--------------------------------------------------+
| Uwe-Krischna Tantz | Tel/Fax: +49 941 / 56 31 40 |
| Hackengaesschen 4 | EMail: uwe.tantz@physik.uni-regensburg.de |
| 93047 Regensburg | |
+---------------------+--------------------------------------------------+
Author: thoff@falcon.depaul.edu (Timothy E. Hoff)
Date: 1995/06/19 Raw View
I have followed some of the discussion about empty arrays in C so I
don't think that I am repeating anyone.
In C, arrays are defined statically at compile time. Therefore, it seems
reasonable for a compiler to refuse to compile something which must always
be unusable (because the name of any array is its const address).
I hope this helps clarify the original question.
--teh
--
Timothy E. Hoff "We will encourage you to develop the
Dept of CS/IS three great virtues of a programmer:
DePaul University laziness, impatience and hubris."
tel. 708/320-2958 - L. Wall & R. Schwartz
Author: walter briscoe <walter@wbriscoe.demon.co.uk>
Date: 1995/06/19 Raw View
In article <Pine.SOL.3.90.950619120252.23183A-100000@rphc4>
c4037 "uwe.tantz" writes:
> zero-lengthed arrays are often used in windows-api (although I think
> it is dirty C(--) manner)
>
> They are reasonable if you cast a memory block to a struct, the last element
> of which is a zero lengthed array.
>
> Look at this (for example):
>
> struct TBitmap
> {
> long NumberOfBytes;
> char Bitmap[0];
> };
>
> void DisplayBitmap (int Id)
> {
> char* Buffer = LoadResource (Id);
> TBitmap* Picture = (TBitmap*) Buffer;
> DoSomething (Picture);
> }
>
> Of course this may lead to problems if you want to copy the struct, but
> I have seen constructs like this not just once.
I agree its dirty and does not fit with the standard. With implementation
specific requirements like this, who cares? I suggest the immediate departure
from the standard can be dealt with by
char Bitmap [ 1 ] ;
or where bounds-checking is in place
char Bitmap [ ( size_t ) ( ~ ( ( unsigned long ) 0 ) ) ] ;
I apologize for not checking the latter construct with the standard. PC-Lint
accepted it when validating as C++.
The code can be made slightly safer against using the name to access objects
rather than pointers to objects by commenting the declaration and only
naming the pointer. i.e.
/*
** pTBitmap is used as a pointer to a resource to treat it as a bitmap.
*/
typedef struct
{
long NumberOfBytes ;
char Bitmap [ 1 ] ; /* Pseudo-array: logically [ NumberOfBytes ] */
} * pTBitmap ;
In your example: can NumberOfBytes be -ve or zero? If not, I would prefer a type
which conveyed that information. Similarly, is char good enough? Is signed char
or unsigned char better? None of which as anything to do with the language
standard. IMO, the most important feature of code is to express the thought of
the author to be understood by another person. (Including the author later.)
Apologies for motherhood sentiments.
--
walter briscoe
Author: osinski@valis.cs.nyu.edu (Ed Osinski)
Date: 1995/06/20 Raw View
In article <3s0v93$sk7@fu-berlin.de>, axl@zedat.fu-berlin.de (Axel Thimm) writes:
|> In article <3rtv8u$jga@network.ucsd.edu>, raymondc@beer.extern.ucsd.edu
|> says...
|> >
|> >Consider
|> >
|> > struct NADA { char x[0]; } a[2];
|> >
|> >and remember that the following expressions must all evaluate true.
|> >
|> >1) sizeof(a) == sizeof(a[0]) * 2
|> >2) &a[0] != &a[1]
|> >3) &a[1] - &a[0] == 1
|> >4) (char *)&a[0] + sizeof(a[0]) == (char*)&a[1]
|> >
|> >This puts you in a bit of a pickle.
|>
|> Empty classes and structures are also allowed, why shouldn't empty arrays be
|> also accepted, but not be useable (no subscribing possible, sizeof returns
|> 1, ...)?
To expand on this, since empty structs are allowed (at least in C++),
and have a sizeof 1, why would putting a zero-length array into an
otherwise empty struct make it smaller? I assume that empty structs
are allowed in C as well. Just out of curiosity, can anyone confirm
or deny?
I finally can see a problem though. Consider the sizeof a zero-length
array. In general, we have:
T a[N];
sizeof(a) == sizeof(T) * N // guaranteed
This would lead one to believe that the sizeof a zero-length array is
0. This conflicts with the desire to have every construct be of
non-zero size (which is why the sizeof an empty struct is 1). I guess
rather than have to decide one way or the other, zero-length arrays
were simply disallowed. Oh well!
--
---------------------------------------------------------------------
Ed Osinski
Computer Science Department, New York University
E-mail: osinski@cs.nyu.edu
---------------------------------------------------------------------
"No, no, no, don't tug on that. You never know what it might be attached to."
-- Buckaroo Bonzai to assistant during brain surgery
Author: axl@zedat.fu-berlin.de (Axel Thimm)
Date: 1995/06/18 Raw View
In article <3rtv8u$jga@network.ucsd.edu>, raymondc@beer.extern.ucsd.edu
says...
>
>In article <3rsrhr$1mq@cmcl2.NYU.EDU>, Ed Osinski <osinski@cs.nyu.edu>
wrote:
>>In article <3rsi2u$dpp@bb29c.mdd.comm.mot.com>, mitchell@mdd.comm.mot.com
(Bill
> Mitchell) writes:
>>|> From the ANSI C Standard: [3.5.4.2]
>>Ok, now the questions are: why does C disallow this[...]
>
>Consider
>
> struct NADA { char x[0]; } a[2];
>
>and remember that the following expressions must all evaluate true.
>
>1) sizeof(a) == sizeof(a[0]) * 2
>2) &a[0] != &a[1]
>3) &a[1] - &a[0] == 1
>4) (char *)&a[0] + sizeof(a[0]) == (char*)&a[1]
>
>This puts you in a bit of a pickle.
Empty classes and structures are also allowed, why shouldn't empty arrays be
also accepted, but not be useable (no subscribing possible, sizeof returns
1, ...)?
Axel Thimm
Author: Dan.Pop@mail.cern.ch (Dan Pop)
Date: 1995/06/18 Raw View
In <3s0v93$sk7@fu-berlin.de> axl@zedat.fu-berlin.de (Axel Thimm) writes:
>Empty classes and structures are also allowed, why shouldn't empty arrays be
ANSI C doesn't allow empty structures.
>also accepted, but not be useable (no subscribing possible, sizeof returns
>1, ...)?
Why should sizeof return 1 when the size of the object is 0? If this
makes any sense, I fail to see it. Padding structures is permitted,
padding arrays, AFAIK, isn't :-)
gcc supports, as an extension (or as a GNU C feature :-) empty arrays,
but it correctly reports their size as being 0.
Dan
--
Dan Pop
CERN, CN Division
Email: Dan.Pop@mail.cern.ch
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
Author: "Ronald F. Guilmette" <rfg@rahul.net>
Date: 1995/06/18 Raw View
In article <3rrhn4$b3n@fu-berlin.de>,
Axel Thimm <axl@zedat.fu-berlin.de> wrote:
>I am writing a program using some templates. In one template I use a template
>integral argument (<int dim>). In the classes definition, there is an array
>with the following definition:
>
> int coordsbutlast[dim-1];
>
>Since the program should theoretically work in the one dimesional case also,
>I tried it out with dim = 1. My compiler (gcc 2.6.3.) did not complain about
>this, but I don't think, that this is the standard behaviour for an ANSI C or
>ANSI C++ compiler (gcc does have some special enhancements, like local
>arrays). Does anyone know anything about arrays with zero length? Are or
>aren't these defined in the standards?...
Arrays with zero length are disallowed by the ISO C standard. I believe
that this is also true in the draft C++ standard, but I'm less sure in
that case.
The GNU compilers allow zero length arrays as a non-standard language
extension. If you want your code to be portable to other compilers which
do not provide this or other non-standard GNU extensions, use the
-pedantic-errors option when compiling.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- E-mail: rfg@segfault.us.com ----------- Purveyors of Compiler Test ----
---- finger: rfg@rahul.net ----------------- Suites and Bullet-Proof Shoes -
Author: axl@zedat.fu-berlin.de (Axel Thimm)
Date: 1995/06/16 Raw View
I am writing a program using some templates. In one template I use a template
integral argument (<int dim>). In the classes definition, there is an array
with the following definition:
int coordsbutlast[dim-1];
Since the program should theoretically work in the one dimesional case also,
I tried it out with dim = 1. My compiler (gcc 2.6.3.) did not complain about
this, but I don't think, that this is the standard behaviour for an ANSI C or
ANSI C++ compiler (gcc does have some special enhancements, like local
arrays). Does anyone know anything about arrays with zero length? Are or
aren't these defined in the standards? I'd like to make my program as
portable as possible.
Many thanks in advance,
Axel Thimm
Author: Dan.Pop@mail.cern.ch (Dan Pop)
Date: 1995/06/16 Raw View
In <3rrhn4$b3n@fu-berlin.de> axl@zedat.fu-berlin.de (Axel Thimm) writes:
>I am writing a program using some templates. In one template I use a template
>integral argument (<int dim>). In the classes definition, there is an array
>with the following definition:
>
> int coordsbutlast[dim-1];
>
>Since the program should theoretically work in the one dimesional case also,
>I tried it out with dim = 1. My compiler (gcc 2.6.3.) did not complain about
>this, but I don't think, that this is the standard behaviour for an ANSI C or
>ANSI C++ compiler (gcc does have some special enhancements, like local
>arrays). Does anyone know anything about arrays with zero length? Are or
>aren't these defined in the standards? I'd like to make my program as
>portable as possible.
>
The ANSI/ISO C standard doesn't support zero sized objects. You can
convince yourself of this, using gcc, which is pretty good at checking
ANSI conformance, provided you use the right options :-)
ues5:~/tmp 67> cat test.c
int main()
{
int array[0];
return 0;
}
ues5:~/tmp 68> gcc test.c
ues5:~/tmp 69> gcc -pedantic test.c
test.c: In function `main':
test.c:3: warning: ANSI C forbids zero-size array `array'
Dan
--
Dan Pop
CERN, CN Division
Email: Dan.Pop@mail.cern.ch
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
Author: lhecking@nmrc.ucc.ie (Lars Hecking)
Date: 1995/06/16 Raw View
In article <3rrhn4$b3n@fu-berlin.de> axl@zedat.fu-berlin.de (Axel Thimm) writes:
I am writing a program using some templates. In one template I use a
template integral argument (<int dim>). In the classes definition, there is
an array with the following definition:
int coordsbutlast[dim-1];
Since the program should theoretically work in the one dimesional case also,
I tried it out with dim = 1. My compiler (gcc 2.6.3.) did not complain
about this, but I don't think, that this is the standard behaviour for an
ANSI C or ANSI C++ compiler (gcc does have some special enhancements, like
local arrays). Does anyone know anything about arrays with zero length? Are
or aren't these defined in the standards? I'd like to make my program as
portable as possible.
Gcc does indeed take advantage of zero length arrays, but this is not ANSI.
K&R2 A8.6.2 does clearly state that in
D1[constant-expression_{opt}]
constant-expression, if present, must have a value greater than zero.
The same applies to C++ (ANSI C++ draft from 28/4/95, Ch. 8.3.4).
Hope this helps.
--
Lars G. Hecking lhecking@nmrc.ucc.ie
GE/Mgc[failed] d--- H+>H--- s:->s++ g+ p0>? !au a- w+ v+>v++ C(+++) US++
P+>+++ L>L++ 3- E+ N+ K- W-->--- M- V- -po+ Y+ t+ 5 !j R
G? tv- b+ D-- B? e++++ u++(-) h* f r++ n+ y+*
Author: mitchell@mdd.comm.mot.com (Bill Mitchell)
Date: 1995/06/16 Raw View
in comp.std.c, axl@zedat.fu-berlin.de (Axel Thimm) said:
>I am writing a program using some templates. In one template I use a template
>integral argument (<int dim>). In the classes definition, there is an array
>with the following definition:
>
> int coordsbutlast[dim-1];
>
>Since the program should theoretically work in the one dimesional case also,
>I tried it out with dim = 1. My compiler (gcc 2.6.3.) did not complain about
>this, but I don't think, that this is the standard behaviour for an ANSI C or
>ANSI C++ compiler (gcc does have some special enhancements, like local
>arrays). Does anyone know anything about arrays with zero length? Are or
>aren't these defined in the standards? I'd like to make my program as
>portable as possible.
Author: osinski@valis.cs.nyu.edu (Ed Osinski)
Date: 1995/06/16 Raw View
In article <3rsi2u$dpp@bb29c.mdd.comm.mot.com>, mitchell@mdd.comm.mot.com (Bill Mitchell) writes:
|> From the ANSI C Standard:
|>
|> 3.5.4.2 Array Declarators
|>
|> Constraints
|>
|> The expression delimited by [ and ] (which specifies the size of
|> an arrya) shall be an integral constant expression that has a
|> value greater than zero.
Ok, now the questions are: why does C disallow this, and secondly, why
does C++ disallow this? In C++ at least, it would be useful in
forcing alignment of succeeding declarations within a class.
|> mitchell@mdd.comm.mot.com (Bill Mitchell)
--
---------------------------------------------------------------------
Ed Osinski
Computer Science Department, New York University
E-mail: osinski@cs.nyu.edu
---------------------------------------------------------------------
"No, no, no, don't tug on that. You never know what it might be attached to."
-- Buckaroo Bonzai to assistant during brain surgery