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

declaration meaning

0 views
Skip to first unread message

krishna

unread,
May 5, 2006, 12:21:09 PM5/5/06
to
Hi all,
char a[10];
will declare character array of size 10 starting with the index 0.
what is the meaning of the following declaration? what is the purpose
of such
declarations?
char a[0];

thanks,
Krishna

Darko

unread,
May 5, 2006, 2:15:13 PM5/5/06
to
It's illegal. Compiler would complain. If you said for example
char a[1];
it would be one character, and the A would be a pointer to it.
Specifying zero sized arrays is illegal.

Roberto Waltman

unread,
May 5, 2006, 2:20:26 PM5/5/06
to
"krishna" <krishna...@gmail.com> wrote:

They are used sometimes to provide a name for a variable size array,
located at the adress of 'a'.
For example:

#include <stdlib.h>

struct message
{
int type;
int length;
char data[0];
};
typedef struct message message_t;

message_t *create_message(int type, int length)
{
message_t *temp;
temp = malloc(length + sizeof(message_t));
if (temp != NULL)
{
temp->type = type;
temp->length = length;
}
return temp;
}

int main()
{
message_t *abc;
abc = create_message(10);
return EXIT_SUCCESS;
}

Darko

unread,
May 5, 2006, 2:32:45 PM5/5/06
to
If this works, then it's a work of art. :) Of course - if one was to
declare it as a variable, it would get a compiler error. However,
declaring it in a structure doesn't do the allocating itself, we just
get a name we later hold for when referring to (m)allocated memory.
Genialno. :) So, it actually works only for structs?

krishna

unread,
May 5, 2006, 2:51:08 PM5/5/06
to
thanks for the info
sizeof(message_t) + length is allocated
How can we assign value to the member "data" of the structure message
After the allocation is "data" an character array of size 10?

thanks,
Krishna

krishna

unread,
May 5, 2006, 2:53:10 PM5/5/06
to
yes actually in the code i am reading it is actually inside the
structure.
Sorry i just mentioned it as a variable

Roberto Waltman

unread,
May 5, 2006, 3:04:31 PM5/5/06
to
"krishna" <krishna...@gmail.com> wrote:
> sizeof(message_t) + length is allocated
>How can we assign value to the member "data" of the structure message
>After the allocation is "data" an character array of size 10?

Surprisingly, by using data[i], where i is declared as an integer type
and (i >= 0) and (i < 10).
Or any other way allowed by the C language...

krishna

unread,
May 5, 2006, 3:18:24 PM5/5/06
to
yes it works.
thank u so much!!!

void * clvrmnky()

unread,
May 5, 2006, 3:18:52 PM5/5/06
to
Roberto Waltman wrote:
> "krishna" <krishna...@gmail.com> wrote:
>
>> Hi all,
>> char a[10];
>> will declare character array of size 10 starting with the index 0.
>> what is the meaning of the following declaration? what is the purpose
>> of such
>> declarations?
>> char a[0];
>
> They are used sometimes to provide a name for a variable size array,
> located at the adress of 'a'.
> For example:
>
> #include <stdlib.h>
>
> struct message
> {
> int type;
> int length;
> char data[0];
> };

Is this strictly Standard ISO C? I know that GCC allows this form of an
array that forms a variable-length object. C90 wants it to be "char
data[1];" and C99 indicates that is should be "char data[];"

Roberto Waltman

unread,
May 5, 2006, 3:32:49 PM5/5/06
to
On Fri, 05 May 2006 14:20:26 -0400, Roberto Waltman
>They are used sometimes to provide a name for a variable size array,
>located at the adress of 'a'.
>For example:
>
>#include <stdlib.h>
>
>struct message
>{
> int type;
> int length;
> char data[0];
>};
>typedef struct message message_t;
>
>message_t *create_message(int type, int length)
>{
> message_t *temp;
> temp = malloc(length + sizeof(message_t));
> if (temp != NULL)
> {
> temp->type = type;
> temp->length = length;
> }
> return temp;
>}
>
>int main()
>{
> message_t *abc;
> abc = create_message(10);
Sorry, this call should have two parameters, of course.

> return EXIT_SUCCESS;
>}

I think I misunderstood Krishna's 2nd question.
In this example the array could be accessed as
abc->data, abc->data[5], etc.
(If abc is not NULL).

Eric Sosman

unread,
May 5, 2006, 3:35:26 PM5/5/06
to

void * clvrmnky() wrote On 05/05/06 15:18,:


> Roberto Waltman wrote:
>
>>"krishna" <krishna...@gmail.com> wrote:
>>
>>
>>>Hi all,
>>>char a[10];
>>>will declare character array of size 10 starting with the index 0.
>>>what is the meaning of the following declaration? what is the purpose
>>>of such
>>>declarations?
>>>char a[0];
>>
>>They are used sometimes to provide a name for a variable size array,
>>located at the adress of 'a'.
>>For example:
>>
>>#include <stdlib.h>
>>
>>struct message
>>{
>> int type;
>> int length;
>> char data[0];
>>};
>
>
> Is this strictly Standard ISO C?

No.

--
Eric....@sun.com

Roberto Waltman

unread,
May 5, 2006, 3:45:26 PM5/5/06
to

No. Thanks for pointing this out. From ISO/IEC-9899 2nd edition:

"6.7.5.2 Array declarators
Constraints
1 In addition to optional type qualifiers and the keyword static, the
[ and ] may delimit an expression or *. If they delimit an expression
(which specifies the size of an array), the expression shall have an
integer type. If the expression is a constant expression, it shall
have a value greater than zero."

Keith Thompson

unread,
May 5, 2006, 4:26:02 PM5/5/06
to
Roberto Waltman <use...@rwaltman.net> writes:

> "krishna" <krishna...@gmail.com> wrote:
>>char a[10];
>> will declare character array of size 10 starting with the index 0.
>>what is the meaning of the following declaration? what is the purpose
>>of such
>>declarations?
>>char a[0];
>
> They are used sometimes to provide a name for a variable size array,
> located at the adress of 'a'.
> For example:
>
[...]

>
> struct message
> {
> int type;
> int length;
> char data[0];
> };
[...]

This is not legal in standard C, though some compilers may allow it as
an extension. Another common way to express this is by declaring
char data[1];

Both forms are known as the "struct hack". C99 provides a new
features called "flexible array members", intended to provide the
functionality of the struct hack in a clearly legal manner.

--
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.

Keith Thompson

unread,
May 5, 2006, 6:14:01 PM5/5/06
to

What are you talking about?

Please read <http://cfaj.freeshell.org/google/>.

CBFalconer

unread,
May 5, 2006, 5:50:27 PM5/5/06
to

Very clear. It is obvious to all what 'it' means. I suggest you
try reading your own posts before hitting the equivalent of a
'send' key, and seeing if it makes sense. Without context most
posts do not. To include suitable context, even with the insipidly
stupid google interface to usenet, see my sig. below.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>


dahuaxiy...@gmail.com

unread,
May 5, 2006, 9:49:35 PM5/5/06
to
i try the code in vs.net,it can not pass.
does it only work in gcc?

Ian Collins

unread,
May 5, 2006, 10:55:23 PM5/5/06
to
dahuaxiy...@gmail.com wrote:
> i try the code in vs.net,it can not pass.
> does it only work in gcc?
>
Please quote context.

The code will not compile in gcc (create_message is only called with one
parameter), the struct will compile with a warning.

Other compilers will correctly reject it.

--
Ian Collins.

Tomás

unread,
May 6, 2006, 10:10:58 AM5/6/06
to

> #include <stdlib.h>
>
> struct message
> {
> int type;
> int length;
> char data[0];
> };
> typedef struct message message_t;
>
> message_t *create_message(int type, int length)
> {
> message_t *temp;
> temp = malloc(length + sizeof(message_t));
> if (temp != NULL)
> {
> temp->type = type;
> temp->length = length;
> }
> return temp;
> }
>
> int main()
> {
> message_t *abc;
> abc = create_message(10);
> return EXIT_SUCCESS;
> }


In C, we can declare arrays of objects as follows:

message array[4];

And we're guaranteed that each element is DIRECTLY after the other in
memory, such that we can use a pointer like so:

message *p = &array[0];
++p; //now it points to the 2nd element
++p; //now it points to the 3rd element
++p; //now it points to the 4th element

To facilitate this, the "sizeof" operator returns the full size of the
struct including any necessary padding at the end, such that the next
element in an array can be directly after it.

So, if you define a struct as follows:

struct Monkey { int i; int k; char b; };

It is very probable that it will take up the following amount of memory:

a) 4 bytes for "i"
b) 4 bytes for "k"
b) 1 byte for "b"
c) 3 bytes of padding so the next element can be right after it.

This gives us an overall size of 12 bytes.

Now here's my question:

If we define a structure which has an array at the end of it, how can we be
sure that there's no padding at the end?

-Tomás

Walter Roberson

unread,
May 6, 2006, 11:14:37 AM5/6/06
to
In article <S727g.8782$j7.3...@news.indigo.ie>, Tomás <NU...@NULL.NULL> wrote:

>Now here's my question:

>If we define a structure which has an array at the end of it, how can we be
>sure that there's no padding at the end?

( ( (char *) &structname + sizeof structname) -
( (char *) &structname.arrayname + sizeof structname.arrayname ) ) == 0

This should be legal because you are allowed to construct pointers
to one element past the end of an object. If I recall a posting
from a few weeks ago correctly, C99 specifically indicates that
such pointers are comparable (so you could test them for
equality instead of subtracting them), but if I remember correctly,
C89 does not specifically indicate you can compare such pointers
to each other [which is why I take their difference, with the
potentially larger value first]

--
Okay, buzzwords only. Two syllables, tops. -- Laurie Anderson

Joe Wright

unread,
May 6, 2006, 11:37:26 AM5/6/06
to

Why do you care that there's padding? sizeof tells you all you need to
know doesn't it?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

Tomás

unread,
May 6, 2006, 3:00:15 PM5/6/06
to

> Why do you care that there's padding? sizeof tells you all you need to
> know doesn't it?

Well consider this:

(I'm still not adjusted to C, so forgive me if I use C++ idioms/styles which
I shouldn't use.)

#include <stdlib.h>

typedef struct Monkey {

int i;
char a[1];

} Monkey;

void SomeFunc( Monkey* const p_monkey )
{
/* Let's get a pointer to the second array element: */

char *pc1 = &p_monkey->a[1];


/* Now let's do that another way: */

char *pc2 = (char*) (p_monkey + 1);


/* ******************************** */


/* Now let's compare the addresses */

if ( pc1 != pc2 )
{
printf("We have padding at the end!");
}
}

int main(void)
{
//Let's say we want that array to
//consist of seven elements:

void* const p = malloc( sizeof(Monkey) + 6 );

Monkey* const p_monkey = (Monkey*)p;

p_monkey->i = 5;

p_monkey->a[0] = 'a';
p_monkey->a[1] = 'b';
p_monkey->a[2] = 'c';
p_monkey->a[3] = 'd';
p_monkey->a[4] = 'e';
p_monkey->a[5] = 'f';
p_monkey->a[6] = 'g';

SomeFunc( p_monkey );


free(p);
}


If there is indeed three bytes of padding at the end of this structure, then
the following l-value:

p_monkey->a[1]

refers to the first byte of padding.

However, the following l-value:

p_monkey + 1

refers to the first byte AFTER the three bytes of padding.

Therefore, it seems that there's not much benefit in the whole "array at the
end of a structure" strategy. It would be just as handy to do the following:


typedef struct Monkey { int i; } Monkey;

int main(void)
{
void* const p = malloc( sizeof(Monkey) + 7 );


Monkey* const p_monkey = (Monkey*)p;


/* Now if we want to access the array: */

char* p_array = (char*) (p_monkey + 1);

p_array[0] = 'a';

p_array[1] = 'b';
}


Then "SomeFunc" could play with the structure as follows:


void SomeFunc( Monkey* const p_monkey )
{
/* Let's get a pointer to the first array element: */

char *p = (char*) (p_monkey + 1);

/* Now access the array: */

p[0] = 'a';
}

It appears to me, that there would only be merit in the method of putting an
array at then end of a struct if the padding was put BEFORE the first array
element, as follows:

a) 4 bytes for "i"

b) 3 bytes of padding.
c) 1st element of the array.


-Tomás

Tomás

unread,
May 6, 2006, 4:11:05 PM5/6/06
to

> And this difference depends upon how the Monkey structure is defined
> (specifically, the length we specify for "array").


Opps I just realized that your code was correct, and that it took into
account the length we specify for "arrayname". I'll try again:

enum { length = 5; };

typedef struct Monkey { int i; char array[length]; } Monkey;

enum bool { false, true };

bool IsTherePaddingAtTheEndOfMonkey(void)
{
Monkey object;

void* const p1 = &object + 1;

void* const p2 = &object.array + 1;

if ( p1 != p2 ) printf( "We have padding!";

/* The amount of padding is determined by: */

(char*)p1 - (char*)p2;
}


-Tomás

Ben C

unread,
May 6, 2006, 5:40:04 PM5/6/06
to
On 2006-05-06, Tomás <NU...@NULL.NULL> wrote:
>
>> Why do you care that there's padding? sizeof tells you all you need to
>> know doesn't it?

[...]

> If there is indeed three bytes of padding at the end of this structure, then
> the following l-value:
>
> p_monkey->a[1]
>
> refers to the first byte of padding.
>
> However, the following l-value:
>
> p_monkey + 1
>
> refers to the first byte AFTER the three bytes of padding.

Yes (a few operators and casts understood), but that doesn't really
matter so long as you don't try to use p_monkey + 1 to find the second
element of the array, but always use p_monkey->a[1].

It means you malloc a bit more than you need-- sizeof (Monkey) + 7
extends the array actually by 7 + padding. But that doesn't really
matter.

> Therefore, it seems that there's not much benefit in the whole "array at the
> end of a structure" strategy. It would be just as handy to do the following:
>
>
> typedef struct Monkey { int i; } Monkey;
>
> int main(void)
> {
> void* const p = malloc( sizeof(Monkey) + 7 );
>
>
> Monkey* const p_monkey = (Monkey*)p;
>
>
> /* Now if we want to access the array: */
>
> char* p_array = (char*) (p_monkey + 1);
>
> p_array[0] = 'a';
>
> p_array[1] = 'b';
> }

Yes, this also works. Then you wouldn't bother with the char a[1] at the
end of struct Monkey presumably. It would be positively misleading to
leave it in there.

It's less convenient this way though, because you have to use casts to
get at that array, and the user of the array (SomeFunc say) has to know
what type to cast to. If we have that char a[1], we know at least that
it's an array of char (or whatever else), and we just use it
transparently as if it were a larger array.

> Then "SomeFunc" could play with the structure as follows:
>
>
> void SomeFunc( Monkey* const p_monkey )
> {
> /* Let's get a pointer to the first array element: */
>
> char *p = (char*) (p_monkey + 1);
>
> /* Now access the array: */
>
> p[0] = 'a';
> }

> It appears to me, that there would only be merit in the method of
> putting an array at then end of a struct if the padding was put BEFORE
> the first array element, as follows:
>
> a) 4 bytes for "i"
> b) 3 bytes of padding.
> c) 1st element of the array.

This sounds like it could work, and I think the compiler could
legitimately do it that way if it felt like it; then (p_monkey + 1 ==
&p_monkey->array[1]). But it doesn't matter in practice that these are
not equal, so long as you don't use p_monkey + 1 to get to the second
element of the extended array.

michi

unread,
May 7, 2006, 2:23:57 PM5/7/06
to
Darko schrieb:
work of art? I'd say that's a landmine.

- Anyone unsuspiciously using a memcpy(pX,pFoo,sizeof(*pFoo)) will get
surprising results.

- Using malloc, one must take into account that the storage for the
first element is covered by sizeof(stuct message) while the rest is not.

- for copying you should at least provide a size_t len member to
determine the "extra" space.

- it makes your code wide open for heap-overflow attacks and code
injection exploits.

- It's impossible to have these objects on the stack, even if the
compiler permits it.

- Consider using #pragma pack(1) struct ... #pragma pack()
this will provide you at least with defined memory-layouts you are using
reinterpret-casts to the "char" data, even if packing was modified from
somewhere else. (cc options, foreign headers)

I'd suggest not to use this construct even if it's convenient.

<flame mode="plenty">
variable sized array are pure evil
</flame>

Keith Thompson

unread,
May 7, 2006, 8:51:20 PM5/7/06
to
michi <sp...@reppisch.de> writes:
> Darko schrieb:
>> If this works, then it's a work of art. :) Of course - if one was to
>> declare it as a variable, it would get a compiler error. However,
>> declaring it in a structure doesn't do the allocating itself, we just
>> get a name we later hold for when referring to (m)allocated memory.
>> Genialno. :) So, it actually works only for structs?
>>
> work of art? I'd say that's a landmine.

The technique described in the previous article is the "struct hack",
a very well-known technique. C99 adds "flexible array members" (q.v.)
that do the same thing.

> - Anyone unsuspiciously using a memcpy(pX,pFoo,sizeof(*pFoo)) will get
> surprising results.

Yes, you have to be careful.

> - Using malloc, one must take into account that the storage for the
> first element is covered by sizeof(stuct message) while the rest is
> not.

Yes.

> - for copying you should at least provide a size_t len member to
> determine the "extra" space.

Yes.

> - it makes your code wide open for heap-overflow attacks and code
> injection exploits.

How so? If you manage memory carefully enough, this shouldn't be an
issue.

> - It's impossible to have these objects on the stack, even if the
> compiler permits it.

Yes.

> - Consider using #pragma pack(1) struct ... #pragma pack()
> this will provide you at least with defined memory-layouts you are
> using reinterpret-casts to the "char" data, even if packing was
> modified from somewhere else. (cc options, foreign headers)

"#pragma pack" is non-standard and non-portable. Use it if you must,
but I don't see how it helps in using the "struct hack". (And C
doesn't have "reinterpret-casts"; that's a C++ term.)

0 new messages