By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,837 Members | 1,358 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,837 IT Pros & Developers. It's quick & easy.

Zero length array declaration

P: n/a
RS
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS
Nov 14 '05 #1
Share this Question
Share on Google+
31 Replies


P: n/a
RS wrote:
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?


The construct as written is not legal C under either
version of the Standard, although some compilers may allow
it as an extension to the language.

Declaring `bar' as a one-element array is and always has
been legal. However, allocating extra memory for the struct
and then using `bar' as if it had more than one element is
not. This particular abuse (known as "the struct hack") works
on the great majority of C implementations, but is not actually
legitimate.

The latest "C99" version of the Standard legitimizes the
struct hack, but introduces a new syntax: you declare `bar'
with no array size at all, as `char bar[]'. However, this is
still relatively new and not yet widely supported by available
compilers.

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

Nov 14 '05 #2

P: n/a
> Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

I not sure about the legality of this - others can answer that.

For the stated purpose this is wrong.

char bar[0] should be char *bar instead. That's what a
pointer is for - to refer or point to some storage located
somewhere else.
Nov 14 '05 #3

P: n/a
jj******@yahoo.com (jjr2004a) writes:
Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

I not sure about the legality of this - others can answer that.

For the stated purpose this is wrong.

char bar[0] should be char *bar instead. That's what a
pointer is for - to refer or point to some storage located
somewhere else.


No, the point of declaring bar as an array is that the array (of some
dynamic size) is stored within the struct itself. The structure is
allocated by calling malloc with a size equal to the size of the
structure itself plus the number of characters to be stored in the
array. It's called the "struct hack"; it's commonly supported, and
commonly used, but not strictly legal.

Declaring "char *bar" is of course valid as well, but it's a different
thing, requiring a separate memory allocation (and later deallocation)
for the array.

As others have said elsethread, C99 adds support for the struct hack,
but with a new syntax.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #4

P: n/a

"RS" <rs*******@gmail.com> wrote in message
news:7d**************************@posting.google.c om...
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS


Strictly speaking, accessing an array beyond its bounds results in undefined
behaviour according to the Standard.
Nov 14 '05 #5

P: n/a
"Method Man" <a@b.c> writes:
"RS" <rs*******@gmail.com> wrote in message
news:7d**************************@posting.google.c om...
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS


Strictly speaking, accessing an array beyond its bounds results in undefined
behaviour according to the Standard.


Strictly speaking, declaring a 0-sized array is illegal. Some
compilers may let you get away with it. Compilers that disallow
0-sized arrays may let you implement the struct hack with
char bar[1];
The declaration is legal, but accessing elements beyond bar[0] invokes
undefined behavior (which, if you've allocated enough memory, is
likely to work aryway).

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #6

P: n/a
"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@nuthaus.mib.org...
"Method Man" <a@b.c> writes:
"RS" <rs*******@gmail.com> wrote in message
news:7d**************************@posting.google.c om...
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.
If you want "to have the structure above point to a message buffer", you
should use a pointer to a buffer containing a message. This buffer could
be an array of strings, for instance.
My question is: Is it legal to declare an array with zero length? Or should bar have been declared to be at least one element in length?


Strictly speaking, accessing an array beyond its bounds results in undefined behaviour according to the Standard.


Strictly speaking, declaring a 0-sized array is illegal. Some
compilers may let you get away with it. Compilers that disallow
0-sized arrays may let you implement the struct hack with
char bar[1];
The declaration is legal, but accessing elements beyond bar[0] invokes
undefined behavior (which, if you've allocated enough memory, is
likely to work aryway).


Especially if "aryway" means "not very well". I don't understand why you
would even pursue such a line of reasoning when all the OP wants (read:
needs) is to use a pointer. His post indicated what he wanted, so why go
off on unsupported tangents that imply acceptance for arrays of zero
length or whatever. It's a silly thing to run a thread on.

--
Mabden
Nov 14 '05 #7

P: n/a
On Thu, 02 Dec 2004 02:38:56 GMT
"Mabden" <mabden@sbc_global.net> wrote:
"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@nuthaus.mib.org...
"Method Man" <a@b.c> writes:
"RS" <rs*******@gmail.com> wrote in message
news:7d**************************@posting.google.c om...
> Hi,
>
> Looking to see if the following construct is valid:
> typedef struct {
> int foo;
> char bar[0];
> } foobar;
>
> Basically, the idea is to have the structure above point to a message> buffer that has a 4-byte integer followed by a stream of variable
> number of bytes. The structure member "bar" is used to reference the> stream of bytes. The above code compiles fine with a GNU based
PPC> cross-compiler running on Solaris and seems to do the function
> intended.
If you want "to have the structure above point to a message buffer",
you should use a pointer to a buffer containing a message. This buffer
could be an array of strings, for instance.


He does *not* want the structure to point to a buffer containing the
message. The int foo is almost certainly part of the message comming
over a communications link followed by a number of bytes. For instance,
the bytes recieved might be
int 5
byte 1
byte 2
byte 3
byte 4

To do what you suggest the routine receiving this would first have to
allocate memory for the "header" integer and a pointer, allocate another
block for the rest of the message, set up the pointer and also change
where it is sending the data to etc. Also, the entire lot might be
comming in as one block of data so your solution could also meen copying
the data around even more.
> My question is: Is it legal to declare an array with zero length? Or> should bar have been declared to be at least one element in
length?>

Strictly speaking, accessing an array beyond its bounds results in undefined behaviour according to the Standard.


Strictly speaking, declaring a 0-sized array is illegal. Some
compilers may let you get away with it. Compilers that disallow
0-sized arrays may let you implement the struct hack with
char bar[1];
The declaration is legal, but accessing elements beyond bar[0]
invokes undefined behavior (which, if you've allocated enough
memory, is likely to work aryway).


Especially if "aryway" means "not very well". I don't understand why
you would even pursue such a line of reasoning when all the OP wants
(read: needs) is to use a pointer. His post indicated what he wanted,
so why go off on unsupported tangents that imply acceptance for arrays
of zero length or whatever. It's a silly thing to run a thread on.


No, Keith knows EXACTLY what he is tlking about and the OP was taking
exactly the right approach. It is just unfortunate that the C89 standard
did not bless a way of doing it and that the C99 standard did not
include support for [0] and/or the [1] struct hack which had the benefit
of existing practice.

Also, although not covered by the ISO standard it is a very commonly
supported extension. I would even go as far as to reject a compiler on
the basis of it not supporting this and instead select one where it was
supported, where it not for the fact I haven't come across a compiler
where it fails.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #8

P: n/a
Hello,

Keith Thompson <ks***@mib.org> wrote:
Declaring "char *bar" is of course valid as well, but it's a different
thing, requiring a separate memory allocation (and later deallocation)
for the array.


Well, a separate memory allocation is not needed. You can alloc
sizeof(struct) + extra bytes, and then have bar point to "after the
struct".

Or is there anything else in the standard that forbids this?

BTW: A good usage for now using a pointer is IMHO if you use shared
memory between processes, when the shared memory can be mapped to
different memory locations on every process. A pointer is quite useless
in this scenario, but some indices to the char bar[] array are not.

Regards,
Spiro.

--
Spiro R. Trikaliotis
http://www.trikaliotis.net/
http://www.viceteam.org/
Nov 14 '05 #9

P: n/a
On Wed, 01 Dec 2004 16:13:28 -0500, Eric Sosman
<er*********@sun.com> wrote:
Declaring `bar' as a one-element array is and always has
been legal. However, allocating extra memory for the struct
and then using `bar' as if it had more than one element is
not. This particular abuse (known as "the struct hack") works
on the great majority of C implementations, but is not actually
legitimate.
How about (untested code):

typedef struct foo_s FooT;
struct foo_s
{
size_t size;
Foo *next;
};

char *fooAlloc(size_t size)
{
FooT *s = malloc(sizeof(FooT) + size);
if (!s)
{
do_error_handling();
}
s->size = size;
s->next = NULL; /* put it in a list or whatever */
return (char*) &s[1];
}

void fooFree(char *p)
{
FooT *s = (FooT*)(p - sizeof(FooT));
/* do whatever to the structure */
free(s);
}

The standard says that malloc() returns an area aligned for any purpose,
so assigning it to a FooT* is valid. By the definition of array access,
s[1] points to a valid address in the allocated memory beyond the
initial structure. Similarly, converting back for the free() is valid
(assuming that you've been passed a valid pointer, but that's true of
any allocation system).
The latest "C99" version of the Standard legitimizes the
struct hack, but introduces a new syntax: you declare `bar'
with no array size at all, as `char bar[]'. However, this is
still relatively new and not yet widely supported by available
compilers.


I don't think it's necessary (and is currently non-portable), since the
pointer to the 'extra' area can always be accessed by taking the address
of the next structure (or converting to char* and adding sizeof the
structure).

Chris C
Nov 14 '05 #10

P: n/a
"Chris Croughton" <ch***@keristor.net> wrote in message
news:sl******************@ccserver.keris.net...
On Wed, 01 Dec 2004 16:13:28 -0500, Eric Sosman
<er*********@sun.com> wrote:
Declaring `bar' as a one-element array is and always has
been legal. However, allocating extra memory for the struct
and then using `bar' as if it had more than one element is
not. This particular abuse (known as "the struct hack") works
on the great majority of C implementations, but is not actually
legitimate.
How about (untested code):

typedef struct foo_s FooT;
struct foo_s
{
size_t size;
Foo *next;


ITYM: FooT * next;
};

char *fooAlloc(size_t size)
{
FooT *s = malloc(sizeof(FooT) + size);
if (!s)
{
do_error_handling();
}
s->size = size;
s->next = NULL; /* put it in a list or whatever */
return (char*) &s[1];
}

void fooFree(char *p)
{
FooT *s = (FooT*)(p - sizeof(FooT));
/* do whatever to the structure */
free(s);
}

The standard says that malloc() returns an area aligned for any purpose,
so assigning it to a FooT* is valid. By the definition of array access,
s[1] points to a valid address in the allocated memory beyond the
initial structure.
This is an incorrect assumption. The &s[1] is not necessarily
aligned to the largest size. The alignment of &s[1] is only
correctly aligned to the alignment of "struct foo_s", which
may be less than the largest alignment.

Suppose the largest legal alignment is 16, the sizeof(size_t)
is 4, and sizeof(FooT*) is 4. The sizeof(struct foo_s) is 8
and its alignment is 4. The &s[1] yields an 8-byte aligned,
but NOT 16-byte aligned pointer. Thus, you get undefined behavior.

Similarly, converting back for the free() is valid
(assuming that you've been passed a valid pointer, but that's true of
any allocation system).
The latest "C99" version of the Standard legitimizes the
struct hack, but introduces a new syntax: you declare `bar'
with no array size at all, as `char bar[]'. However, this is
still relatively new and not yet widely supported by available
compilers.


I don't think it's necessary (and is currently non-portable), since the
pointer to the 'extra' area can always be accessed by taking the address
of the next structure (or converting to char* and adding sizeof the
structure).


Unless special care is taken to ensure that the total structure
alignment matches the largest alignment, you'll get undefined
behavior.
Nov 14 '05 #11

P: n/a
Chris Croughton wrote:
On Wed, 01 Dec 2004 16:13:28 -0500, Eric Sosman
<er*********@sun.com> wrote:

Declaring `bar' as a one-element array is and always has
been legal. However, allocating extra memory for the struct
and then using `bar' as if it had more than one element is
not. This particular abuse (known as "the struct hack") works
on the great majority of C implementations, but is not actually
legitimate.

How about (untested code):

typedef struct foo_s FooT;
struct foo_s
{
size_t size;
Foo *next;


ITYM `FooT' here.
};

char *fooAlloc(size_t size)
{
FooT *s = malloc(sizeof(FooT) + size);
`sizeof *s + size' would be slightly better, but
does the same thing.
if (!s)
{
do_error_handling();
}
s->size = size;
s->next = NULL; /* put it in a list or whatever */
return (char*) &s[1];
When I use this trick, I usually write `(char*)(s + 1)',
which means exactly the same thing but (I think) makes my
intention just a tiny bit clearer to the reader. IMHO.
}

void fooFree(char *p)
{
FooT *s = (FooT*)(p - sizeof(FooT));
/* do whatever to the structure */
free(s);
}

The standard says that malloc() returns an area aligned for any purpose,
so assigning it to a FooT* is valid. By the definition of array access,
s[1] points to a valid address in the allocated memory beyond the
initial structure. Similarly, converting back for the free() is valid
(assuming that you've been passed a valid pointer, but that's true of
any allocation system).


Sure -- but there's no array at all in this code,
and it isn't "the struct hack." You're achieving the
same memory layout the hack aims for, but you've lost
the syntactic convenience of being able to refer to
the extra space as if it were a struct element. I use
this technique fairly commonly when there's a string
of some sort associated with the struct, but to reclaim
the syntactic sugar I go ahead and "waste" a `char*'
struct element pointing to the string that immediately
follows the struct itself.

Note that trafficking in the "midpoint pointer" instead
of in the pointer to the `FooT' itself is an orthogonal
matter. It's legal, it works, but it gives up *all* chance
of accessing the other struct members conveniently. I don't
see much point to it.
The latest "C99" version of the Standard legitimizes the
struct hack, but introduces a new syntax: you declare `bar'
with no array size at all, as `char bar[]'. However, this is
still relatively new and not yet widely supported by available
compilers.


I don't think it's necessary (and is currently non-portable), since the
pointer to the 'extra' area can always be accessed by taking the address
of the next structure (or converting to char* and adding sizeof the
structure).


Yes, and if your tolerance for ugliness is high enough you
can even extend the technique to handle "extra" data of a type
with stricter alignment requirements than `char'. C99's "struct
un-hack" lets you achieve the same effect without all the grunge
*and* retains the syntactic convenience of letting you refer to
the "extra" data as part of the struct. I think that's worth
while; code that's easier to read is code that's less likely to
be written wrongly.

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

Nov 14 '05 #12

P: n/a
On Thu, 02 Dec 2004 17:44:12 GMT, xarax
<xa***@email.com> wrote:
"Chris Croughton" <ch***@keristor.net> wrote in message
news:sl******************@ccserver.keris.net...

Foo *next;
ITYM: FooT * next;


Yup. I said it was untested (typing rather than copying).
The standard says that malloc() returns an area aligned for any purpose,
so assigning it to a FooT* is valid. By the definition of array access,
s[1] points to a valid address in the allocated memory beyond the
initial structure.


This is an incorrect assumption. The &s[1] is not necessarily
aligned to the largest size. The alignment of &s[1] is only
correctly aligned to the alignment of "struct foo_s", which
may be less than the largest alignment.


Read what I said. I did not say that it was aligned to the "largest
size". If you look at the code, it only needs to be aligned to a char,
and all other types are at least as big as a char.
Suppose the largest legal alignment is 16, the sizeof(size_t)
is 4, and sizeof(FooT*) is 4. The sizeof(struct foo_s) is 8
and its alignment is 4. The &s[1] yields an 8-byte aligned,
but NOT 16-byte aligned pointer. Thus, you get undefined behavior.
And sizeof(char) is 1 (by definition). It's not undefined at all,
since nothing can have a sizeof less than 1 (although they may all be
equal to 1).
Unless special care is taken to ensure that the total structure
alignment matches the largest alignment, you'll get undefined
behavior.


No, only to the largest alignment needed. In this case, the smallest
alignment will do. But it's easy enough to align to all of the built-in
types, just make a union with all of the largest types (intmax_t, a
pointer, and long double will do), and round up to the next multiple of
that bigger than the size of the structure.

Chris C
Nov 14 '05 #13

P: n/a
RS wrote:
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS


The correct declaration in C99 is:

typedef struct {
int foo;
char bar[];
} foobar;

This will work as intended in any C99 compiler

sizeof(foobar) == sizeof(int);

allocate with
foobar *foo = malloc(sizeof(foobar)+25);
to allocate a "foobar" followed by 25 characters.

jacob
Nov 14 '05 #14

P: n/a
jacob navia wrote:
RS wrote:
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS

The correct declaration in C99 is:

typedef struct {
int foo;
char bar[];
} foobar;

This will work as intended in any C99 compiler

sizeof(foobar) == sizeof(int);


No; sizeof(foobar) >= sizeof(int) is all you can
be sure of. The compiler may insert padding between
the `foo' and `bar' members, even though there seems
no obvious reason to do so in this case.
allocate with
foobar *foo = malloc(sizeof(foobar)+25);
to allocate a "foobar" followed by 25 characters.


malloc(sizeof *foo + 25) would be better.

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

Nov 14 '05 #15

P: n/a
In article <sl******************@ccserver.keris.net>
Chris Croughton <ch***@keristor.net> wrote:
... But it's easy enough to align to all of the built-in
types, just make a union with all of the largest types (intmax_t, a
pointer, and long double will do), and round up to the next multiple of
that bigger than the size of the structure.


This is not *guaranteed*, because implementations are allowed to
be arbitrarily perverse: one could, for instance, make "short *"
and "int *" use four-byte alignment, but make "short **" use
1024-byte alignment, for no good reason.

Realistically, intmax_t from C99 helps a lot, but just those three
-- intmax_t, "a" pointer, and long double -- is probably not
sufficient for existing implementations. You need at least two
pointers, one to data and one to code:

union align {
intmax_t i;
long double ld;
long double *ldp;
void (*fp)(void);
};

is pretty likely to work. (Not guaranteed, just "pretty likely".)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #16

P: n/a
On Thu, 02 Dec 2004 13:00:29 -0500, Eric Sosman
<er*********@sun.com> wrote:
Chris Croughton wrote:

size_t size;
Foo *next;
ITYM `FooT' here.


Yup. I changed my mind after starting to write it what I was going to
call the type.
FooT *s = malloc(sizeof(FooT) + size);


`sizeof *s + size' would be slightly better, but
does the same thing.


I don't like the version of sizeof without parentheses, but yes using
the pointer dereferenced is a little more maintainable.
return (char*) &s[1];


When I use this trick, I usually write `(char*)(s + 1)',
which means exactly the same thing but (I think) makes my
intention just a tiny bit clearer to the reader. IMHO.


I've heard people argue the opposite (and worked in places where each
was compulsory by their coding standards). In my own code I am probably
not consistent (I've also seen (char*)s + sizeof(FooT) proclaimed
better).
Sure -- but there's no array at all in this code,
and it isn't "the struct hack." You're achieving the
same memory layout the hack aims for, but you've lost
the syntactic convenience of being able to refer to
the extra space as if it were a struct element. I use
this technique fairly commonly when there's a string
of some sort associated with the struct, but to reclaim
the syntactic sugar I go ahead and "waste" a `char*'
struct element pointing to the string that immediately
follows the struct itself.
Depending on alignment (and wastage in malloc()) it might waste a lot
more than a char*, but that's a fairly 'clean' way of doing it.
Note that trafficking in the "midpoint pointer" instead
of in the pointer to the `FooT' itself is an orthogonal
matter. It's legal, it works, but it gives up *all* chance
of accessing the other struct members conveniently. I don't
see much point to it.
One point is when the function is being used as a malloc() replacement
(to provide error checking, for instance, or easy heap disposal).
Another is so that the details of implementation can be hidden from the
caller (as in a library which needs to be linked with object modules
where the source is not available). Both are "Real World(TM)" cases
(and the latter is outwith the scope of the standard). And indeed
malloc() and friends often do much the same.
Yes, and if your tolerance for ugliness is high enough you
can even extend the technique to handle "extra" data of a type
with stricter alignment requirements than `char'. C99's "struct
un-hack" lets you achieve the same effect without all the grunge
*and* retains the syntactic convenience of letting you refer to
the "extra" data as part of the struct. I think that's worth
while; code that's easier to read is code that's less likely to
be written wrongly.


The non-portability is still a big issue. I agree that it should have
been there from the start (and indeed many compilers even before the C89
standard allowed a zero length to achieve the same goal) but there are
still too many non-C99 compliant compilers around for me to be
comfortable using it. Putting #ifdefs all over the place to cope with
the variant syntax makes the code unreadable and even less maintainable.

Chris C
Nov 14 '05 #17

P: n/a
Chris Torek <no****@torek.net> writes:
Realistically, intmax_t from C99 helps a lot, but just those three
-- intmax_t, "a" pointer, and long double -- is probably not
sufficient for existing implementations. You need at least two
pointers, one to data and one to code:

union align {
intmax_t i;
long double ld;
long double *ldp;
void (*fp)(void);
};

is pretty likely to work. (Not guaranteed, just "pretty likely".)


I'm not sure why you chose a pointer to long double over a
pointer to void (or to char). If long doubles need 8-byte
alignment, then a pointer to long double could in theory be
shorter than a pointer to void.
--
"...Almost makes you wonder why Heisenberg didn't include postinc/dec operators
in the uncertainty principle. Which of course makes the above equivalent to
Schrodinger's pointer..."
--Anthony McDonald
Nov 14 '05 #18

P: n/a
On 2 Dec 2004 20:40:35 GMT, Chris Torek
<no****@torek.net> wrote:
In article <sl******************@ccserver.keris.net>
Chris Croughton <ch***@keristor.net> wrote:
... But it's easy enough to align to all of the built-in
types, just make a union with all of the largest types (intmax_t, a
pointer, and long double will do), and round up to the next multiple of
that bigger than the size of the structure.


This is not *guaranteed*, because implementations are allowed to
be arbitrarily perverse: one could, for instance, make "short *"
and "int *" use four-byte alignment, but make "short **" use
1024-byte alignment, for no good reason.


Not realistically, because any alignment must be no larger than the size
of the object (otherwise arrays of the object wouldn't work). So if I
had:

short **arr[1024];

and the alignment for a short** was 1024 that would allocate a megabyte
and lots of people would be very unhappy.

I agree about having a function pointer in there as well, that can
easily be a different size from a data pointer.

In practice, though, the most you need is to have one of every basic
type that you want to put into the storage. In one of my applications,
for instance, I use no floating point variables or function pointers so
I'm safe leaving out the long double and the function pointer (and I
create my own IntMax type because I can't guarantee the presence of
stdint.h, or that it will support intmax_t even if it is present).
Since it's likely to be in a separate module (at least, it ought to be)
that module can do all sorts of things involving #ifdefs testing macros
from limits.h (and stdint.h if that is available) and including lots of
types in the union.

(And now I'm singing "You can't get me, I'm part of the union..." It
must be bedtime...)

Chris C
Nov 14 '05 #19

P: n/a
Eric Sosman wrote:
jacob navia wrote:
RS wrote:

Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS


The correct declaration in C99 is:

typedef struct {
int foo;
char bar[];
} foobar;

This will work as intended in any C99 compiler

sizeof(foobar) == sizeof(int);


No; sizeof(foobar) >= sizeof(int) is all you can
be sure of. The compiler may insert padding between
the `foo' and `bar' members, even though there seems
no obvious reason to do so in this case.


Yep. In fact,
sizeof(foobar)==offsetof(foobar,bar)==offsetof(baz ,bar)
for
typedef struct {
int foo;
char bar[1];
} baz;
The last equality is the point which gives the gcc people
such a headache -- they are aligning their equivalent to
flexible array members with more padding (in some cases).
In order to not break existing code or get lost in the
slightly different semantics of bar[0]; vs bar[];, they
decided to sit it out... Apart from the latter innuendo,
more information about this can be found following the
discussion link toward the bottom of
gcc.gnu.org/c99status.html
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #20

P: n/a
>Chris Torek <no****@torek.net> writes:
Realistically, intmax_t from C99 helps a lot, but just those three
-- intmax_t, "a" pointer, and long double -- is probably not
sufficient for existing implementations. You need at least two
pointers, one to data and one to code:

union align {
intmax_t i;
long double ld;
long double *ldp;
void (*fp)(void);
};

is pretty likely to work. (Not guaranteed, just "pretty likely".)

In article <87************@benpfaff.org>
Ben Pfaff <bl*@cs.stanford.edu> wrote:I'm not sure why you chose a pointer to long double over a
pointer to void (or to char). If long doubles need 8-byte
alignment, then a pointer to long double could in theory be
shorter than a pointer to void.


A good point. I wrote the text in ">>" above fairly hastily,
in the few minutes I had between various scheduled interruptions. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #21

P: n/a
In article <co********@news2.newsguy.com>,
Chris Torek <no****@torek.net> wrote:
Chris Torek <no****@torek.net> writes:
Realistically, intmax_t from C99 helps a lot, but just those three
-- intmax_t, "a" pointer, and long double -- is probably not
sufficient for existing implementations. You need at least two
pointers, one to data and one to code:

union align {
intmax_t i;
long double ld;
long double *ldp;
void (*fp)(void);
};

is pretty likely to work. (Not guaranteed, just "pretty likely".)


In article <87************@benpfaff.org>
Ben Pfaff <bl*@cs.stanford.edu> wrote:
I'm not sure why you chose a pointer to long double over a
pointer to void (or to char). If long doubles need 8-byte
alignment, then a pointer to long double could in theory be
shorter than a pointer to void.


A good point. I wrote the text in ">>" above fairly hastily,
in the few minutes I had between various scheduled interruptions. :-)


It is quite possible that double is implemented in hardware and needs
eight byte alignment, while long double is for example 128 bit,
implemented in software using four 32 bit integers, and needs an
alignment of four byte only.
Nov 14 '05 #22

P: n/a
Spiro Trikaliotis <ne*********@trikaliotis.net> writes:
Keith Thompson <ks***@mib.org> wrote:
Declaring "char *bar" is of course valid as well, but it's a different
thing, requiring a separate memory allocation (and later deallocation)
for the array.


Well, a separate memory allocation is not needed. You can alloc
sizeof(struct) + extra bytes, and then have bar point to "after the
struct".

Or is there anything else in the standard that forbids this?


Yes, that's another possible approach. There are some drawbacks. If
you make a copy of the structure, the pointer still points back to the
original structure (for example if you want to expand the array with
realloc()). If the array is of something other than a character type,
there's no good way to align it properly.

Overall, I'd say the classic "struct hack" is a better approach. It's
effectively portable to most or all pre-C99 implementations, and it's
portable to any conforming C99 implementation with a slightly
different syntax. You could probably use it portably with a
preprocessor test for __STDC_VERSION__.

Here's a sample program, that I *think* is portable to all conforming
C99 implementations and to any C90 implementation that supports the
classic struct hack (though in the latter case it may allocate
slightly more memory than it needs to).

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

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#define FLEXIBLE /* empty definition */
#else
#define FLEXIBLE 1
#endif

struct hack {
int len;
char str[FLEXIBLE];
};

#define MESSAGE "hello, world"

int main(void)
{
struct hack *ptr = malloc(sizeof *ptr + sizeof MESSAGE);
ptr->len = strlen(MESSAGE);
strcpy(ptr->str, MESSAGE);
printf("ptr->len = %d\n", ptr->len);
printf("ptr->str = \"%s\"\n", ptr->str);
return 0;
}

As for why C90 didn't choose to bless existing practice, I suspect
that the committee wanted to allow for range-checking implementations.
The struct hack in its classic form depends on being able to access an
array beyond its declared bounds, which invokes undefined behavior but
happens to work. C99 avoided this by introducing a new syntax in
which the array doesn't have declared bounds, so a range-checking
implementation can still do its checking in the normal case.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #23

P: n/a
Keith Thompson wrote:
.... snip ...
Here's a sample program, that I *think* is portable to all conforming
C99 implementations and to any C90 implementation that supports the
classic struct hack (though in the latter case it may allocate
slightly more memory than it needs to).

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

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#define FLEXIBLE /* empty definition */
#else
#define FLEXIBLE 1
#endif

struct hack {
int len;
char str[FLEXIBLE];
};

#define MESSAGE "hello, world"

int main(void)
{
struct hack *ptr = malloc(sizeof *ptr + sizeof MESSAGE);
ptr->len = strlen(MESSAGE);
strcpy(ptr->str, MESSAGE);
printf("ptr->len = %d\n", ptr->len);
printf("ptr->str = \"%s\"\n", ptr->str);
return 0;
}


nitpick: I think you are over allocating space by one byte in C99.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #24

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Keith Thompson wrote:

... snip ...

Here's a sample program, that I *think* is portable to all conforming
C99 implementations and to any C90 implementation that supports the
classic struct hack (though in the latter case it may allocate
slightly more memory than it needs to).

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

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#define FLEXIBLE /* empty definition */
#else
#define FLEXIBLE 1
#endif

struct hack {
int len;
char str[FLEXIBLE];
};

#define MESSAGE "hello, world"

int main(void)
{
struct hack *ptr = malloc(sizeof *ptr + sizeof MESSAGE);
ptr->len = strlen(MESSAGE);
strcpy(ptr->str, MESSAGE);
printf("ptr->len = %d\n", ptr->len);
printf("ptr->str = \"%s\"\n", ptr->str);
return 0;
}


nitpick: I think you are over allocating space by one byte in C99.


I don't think so. I know I'm over-allocating by at least one byte in
C90 (possibly more if there's padding at the end of the structure).
But if I'm wrong, can you explain?

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #25

P: n/a
Keith Thompson wrote:

CBFalconer <cb********@yahoo.com> writes:
Keith Thompson wrote:

... snip ...

Here's a sample program, that I *think* is portable to all conforming
C99 implementations and to any C90 implementation that supports the
classic struct hack (though in the latter case it may allocate
slightly more memory than it needs to).

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

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#define FLEXIBLE /* empty definition */
#else
#define FLEXIBLE 1
#endif

struct hack {
int len;
char str[FLEXIBLE];
};

#define MESSAGE "hello, world"

int main(void)
{
struct hack *ptr = malloc(sizeof *ptr + sizeof MESSAGE);
ptr->len = strlen(MESSAGE);
strcpy(ptr->str, MESSAGE);
printf("ptr->len = %d\n", ptr->len);
printf("ptr->str = \"%s\"\n", ptr->str);
return 0;
}


nitpick: I think you are over allocating space by one byte in C99.


I don't think so. I know I'm over-allocating by at least one byte in
C90 (possibly more if there's padding at the end of the structure).
But if I'm wrong, can you explain?


s/c99/c90/

You are overallocating somewhere :-)

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #26

P: n/a
Eric Sosman wrote:
jacob navia wrote:
RS wrote:

Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS

The correct declaration in C99 is:

typedef struct {
int foo;
char bar[];
} foobar;

This will work as intended in any C99 compiler

sizeof(foobar) == sizeof(int);

No; sizeof(foobar) >= sizeof(int) is all you can
be sure of. The compiler may insert padding between
the `foo' and `bar' members, even though there seems
no obvious reason to do so in this case.


Yes, you are right.

A more portable expression would be:

sizeof(foobar) == offsetof(foobar,bar);

Thanks for the correction

Nov 14 '05 #27

P: n/a
"jacob navia" <ja***@jacob.remcomp.fr> wrote in message
news:41**********************@news.wanadoo.fr...
Eric Sosman wrote:
jacob navia wrote:
RS wrote:
Hi,

Looking to see if the following construct is valid:
typedef struct {
int foo;
char bar[0];
} foobar;

Basically, the idea is to have the structure above point to a message
buffer that has a 4-byte integer followed by a stream of variable
number of bytes. The structure member "bar" is used to reference the
stream of bytes. The above code compiles fine with a GNU based PPC
cross-compiler running on Solaris and seems to do the function
intended.

My question is: Is it legal to declare an array with zero length? Or
should bar have been declared to be at least one element in length?

Comments appreciated.

RS
The correct declaration in C99 is:

typedef struct {
int foo;
char bar[];
} foobar;

This will work as intended in any C99 compiler

sizeof(foobar) == sizeof(int);

No; sizeof(foobar) >= sizeof(int) is all you can
be sure of. The compiler may insert padding between
the `foo' and `bar' members, even though there seems
no obvious reason to do so in this case.


Yes, you are right.

A more portable expression would be:

sizeof(foobar) == offsetof(foobar,bar);

Thanks for the correction


I don't think any conforming compiler will insert
padding bytes between "foo" and "bar", because padding
bytes are only allowed for alignment purposes. The
"bar" member has alignment 1, so it can always be
placed immediately adjacent to "foo" which may have
a larger alignment.
Nov 14 '05 #28

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Keith Thompson wrote:
CBFalconer <cb********@yahoo.com> writes: [...]
> nitpick: I think you are over allocating space by one byte in C99.


I don't think so. I know I'm over-allocating by at least one byte in
C90 (possibly more if there's padding at the end of the structure).
But if I'm wrong, can you explain?


s/c99/c90/

You are overallocating somewhere :-)


Yes.

BTW, I acknowledged the C90 over-allocation when I posted the code.
It didn't seem worthwhile to complicate the code for the sake of such
a small over-allocation, but it could be significant if the array
element is bigger. Now that I think about it, it's easy enough to fix
by using offsetof() rather than sizeof.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #29

P: n/a
"xarax" <xa***@email.com> writes:
[...]
I don't think any conforming compiler will insert
padding bytes between "foo" and "bar", because padding
bytes are only allowed for alignment purposes. The
"bar" member has alignment 1, so it can always be
placed immediately adjacent to "foo" which may have
a larger alignment.


Sure, but the struct hack isn't limited to character arrays.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #30

P: n/a
In <T_************@newsread1.news.pas.earthlink.net > "xarax" <xa***@email.com> writes:
I don't think any conforming compiler will insert
padding bytes between "foo" and "bar", because padding
bytes are only allowed for alignment purposes.
Can I have a chapter and verse for that?
The
"bar" member has alignment 1, so it can always be
placed immediately adjacent to "foo" which may have
a larger alignment.


It is the implementor who decides the optimal alignment for the fields
of a struct, based on his own criteria (and he doesn't even have to
document them). On a platform that doesn't support byte accesses, it
*may* be more efficient to align even arrays of char on word boundaries.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #31

P: n/a
in comp.lang.c i read:
Realistically, intmax_t from C99 helps a lot, but just those three
-- intmax_t, "a" pointer, and long double -- is probably not
sufficient for existing implementations. You need at least two
pointers, one to data and one to code:


better toss in a long double _Complex too.

--
a signature
Nov 14 '05 #32

This discussion thread is closed

Replies have been disabled for this discussion.