Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > char data[0]

Reply
Thread Tools

char data[0]

 
 
aarklon@gmail.com
Guest
Posts: n/a
 
      10-10-2006
Hi all,

this is a question which i saw in a book

typedef struct mall_li_header_ {
int refcnt;
uchar pool;
uchar flag;
ushort magic_no;
char data[0];

} mall_li_header_t;

What is the use of data[0] here ?
to which answer i found from my colleagues as

this is a very old (and common) idea used by a lot of game programmers
from yesteryears.
The answer for completeness sake - common use is : allocate arbitrary
size - anything above the size of the struct can be referenced as
"data".

to what extent this is true?????

 
Reply With Quote
 
 
 
 
Christopher Benson-Manica
Guest
Posts: n/a
 
      10-10-2006
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> this is a question which i saw in a book


(snip struct hack)

> What is the use of data[0] here ?
> to which answer i found from my colleagues as


(snip)

What your colleagues said is similar to the FAQ's content:
http://c-faq.com/struct/structhack.html

--
C. Benson Manica | I *should* know what I'm talking about - if I
cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
 
Reply With Quote
 
 
 
 
Jack Klein
Guest
Posts: n/a
 
      10-11-2006
On 10 Oct 2006 11:56:12 -0700, (E-Mail Removed) wrote in comp.lang.c:

> Hi all,
>
> this is a question which i saw in a book
>
> typedef struct mall_li_header_ {
> int refcnt;
> uchar pool;
> uchar flag;
> ushort magic_no;
> char data[0];
>
> } mall_li_header_t;
>
> What is the use of data[0] here ?
> to which answer i found from my colleagues as
>
> this is a very old (and common) idea used by a lot of game programmers
> from yesteryears.
> The answer for completeness sake - common use is : allocate arbitrary
> size - anything above the size of the struct can be referenced as
> "data".
>
> to what extent this is true?????


What it is actually for is testing for broken compilers, since an
array declaration with a size of 0 has never been allowed in any
version of standard C.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
 
Reply With Quote
 
Old Wolf
Guest
Posts: n/a
 
      10-11-2006
Jack Klein wrote:
> (E-Mail Removed) wrote:
> >
> > typedef struct mall_li_header_ {
> > char data[0];

>
> What it is actually for is testing for broken compilers, since an
> array declaration with a size of 0 has never been allowed in any
> version of standard C.


Compilers are allowed to offer extensions that don't alter the
behaviour of any conforming program.

 
Reply With Quote
 
jmcgill
Guest
Posts: n/a
 
      10-11-2006
(E-Mail Removed) wrote:

> to what extent this is true?????


"none."
 
Reply With Quote
 
jmcgill
Guest
Posts: n/a
 
      10-11-2006
(E-Mail Removed) wrote:

> this is a very old (and common) idea used by a lot of game programmers
> from yesteryears.


I remember a lot of yesteryears' games failing with bizarre memory
problems, especially when running them on later OS versions, with
different memory managers, etc.

If you want an incomplete type, just put a void * in your struct and
allocate that properly. Would that kill you?
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-11-2006
"Old Wolf" <(E-Mail Removed)> writes:
> Jack Klein wrote:
>> (E-Mail Removed) wrote:
>> >
>> > typedef struct mall_li_header_ {
>> > char data[0];

>>
>> What it is actually for is testing for broken compilers, since an
>> array declaration with a size of 0 has never been allowed in any
>> version of standard C.

>
> Compilers are allowed to offer extensions that don't alter the
> behaviour of any conforming program.


Yes, but if the expression is constant and doesn't have a value
greater than zero, it's a constraint violation requiring a diagnostic.
A compiler is free to do what it likes after issuing the diagnostic.
(And of course it's free not to issue the diagnostic in non-conforming
mode; the standard by definition cannot constrain implementations that
don't conform to it.)

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-11-2006
jmcgill <(E-Mail Removed)> writes:
> (E-Mail Removed) wrote:
>
>> this is a very old (and common) idea used by a lot of game programmers
>> from yesteryears.

>
> I remember a lot of yesteryears' games failing with bizarre memory
> problems, especially when running them on later OS versions, with
> different memory managers, etc.
>
> If you want an incomplete type, just put a void * in your struct and
> allocate that properly. Would that kill you?


The struct hack has the advantage that the structure and the array can
be allocated contiguously. It's certainly not legal if you declare
the array with [0], but with [1] it's arguably legal and de facto
portable. It's sufficiently popular that C99 provided a well-defined
version, flexible array members.

See the comp.lang.c FAQ, <http://www.c-faq.com/>, question 2.6.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <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.
 
Reply With Quote
 
Bill Reid
Guest
Posts: n/a
 
      10-11-2006

Keith Thompson <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> jmcgill <(E-Mail Removed)> writes:
> > (E-Mail Removed) wrote:
> >
> >> this is a very old (and common) idea used by a lot of game programmers
> >> from yesteryears.

> >
> > I remember a lot of yesteryears' games failing with bizarre memory
> > problems, especially when running them on later OS versions, with
> > different memory managers, etc.
> >
> > If you want an incomplete type, just put a void * in your struct and
> > allocate that properly. Would that kill you?

>
> The struct hack has the advantage that the structure and the array can
> be allocated contiguously.


Of course, you can allocate a "data" pointer contiguously in a struct
in any event, right?

typedef struct {
unsigned data_type;
unsigned data_size;
unsigned *data;
} contiguous_data_struct;

contiguous_data_struct *my_contiguous_data_struct;

void create_struct(unsigned data_type,unsigned data_size) {
my_contiguous_data_struct=
malloc(sizeof(contiguous_data_struct)+(data_size*s izeof(unsigned));
my_contiguous_data_struct->data_type=data_type;
my_contiguous_data_struct->data_size=data_size;
my_contiguous_data_struct->data=
my_contiguous_data_struct+sizeof(contiguous_data_s truct);
}

And now you may write the data to my_contiguous_data_struct->data(++).

Of course, you wouldn't want to do this for certain types of struct
uses, like an array of structs that you intend to search for data of a
certain type quickly using pointer arithmetic. However, it does allow
you to free the entire schmear using one free().

Right?

---
William Ernest Reid



 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      10-11-2006
>Keith Thompson <(E-Mail Removed)> wrote in message
>news:(E-Mail Removed)...
>> The struct hack has the advantage that the structure and the array can
>> be allocated contiguously.


In article <zY6Xg.51911$(E-Mail Removed)>
Bill Reid <(E-Mail Removed)> wrote:
>Of course, you can allocate a "data" pointer contiguously in a struct
>in any event, right?


Yes; but one crucial fix (and one style nit):

>typedef struct {
> unsigned data_type;
> unsigned data_size;
> unsigned *data;
> } contiguous_data_struct;
>
>contiguous_data_struct *my_contiguous_data_struct;
>
>void create_struct(unsigned data_type,unsigned data_size) {
> my_contiguous_data_struct=
> malloc(sizeof(contiguous_data_struct)+(data_size*s izeof(unsigned));


It is "better style" (at least according to those who think it is
better ) to write this as:

my_contiguous_data_struct =
malloc(sizeof *my_contiguous_data_struct +
data_size * sizeof *my_contiguous_data_struct->data);

That is, apply sizeof to the object(s) being allocated, rather
than their types. That way, if you make a small change to the
data types -- e.g., if you decide to save space by using
"unsigned short" instead of "unsigned int" for the data --
the code automatically follows the change.

> my_contiguous_data_struct->data_type=data_type;
> my_contiguous_data_struct->data_size=data_size;
> my_contiguous_data_struct->data=
> my_contiguous_data_struct+sizeof(contiguous_data_s truct);


This last line needs to add 1, not "sizeof(contiguous_data_struct)"
(nor sizeof *my_contiguous_data_struct). The result has type
"pointer to contiguous_data_struct" -- the same as the type of
the left-hand operand -- so a cast is also required (to
"unsigned *", or perhaps "void *").

Note that, if the compiler is not able to "see" that the
"data" pointer points just past the structure itself, on most
machines you will get some extra (and slightly slower) code
to access the data elements. That is, without the "struct hack":

my_contiguous_data_struct->data[i]

tends to compile into:

- obtain value of my_contiguous_data_struct pointer
- use that value to obtain pointer value my_contiguous_data_struct->data
- obtain value of i, scale if needed, and add to previous
- follow this last pointer to the data

or in machine-code terms:

# assumes "i" is in register r2 at this point
load r1, my_contiguous_data_struct # first step above
load r1, 12(r1) # 2nd step, assuming 4-byte "int"
sll r3, r2, 2 # r3 = r2 * 4 (scale)
add r3, r1, r3 # r3 = &...->data[i]
# now r3 points to my_contiguous_data_struct->data[i]

load r4, (r3) # (if we want to read it)

Using the "struct hack" (or C99's flexible members), on the other
hand, we get to skip one "load" step, perhaps at the cost of an
extra "add", and the machine code becomes more like:

load r1, my_contiguous_data_struct
sll r3, r2, 2
add r3, r1, r3
# now r3 points 12 bytes below my_contiguous_data_struct

load r4, 12(r3)

(this assumes there is a "constant(reg)" offset addressing mode,
but no reg(reg) mode; many machines have both; some even offer
scaling for one of the "reg"s, which can eliminate the shift
instruction).
--
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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
(const char *cp) and (char *p) are consistent type, (const char **cpp) and (char **pp) are not consistent lovecreatesbeauty C Programming 1 05-09-2006 08:01 AM
/usr/bin/ld: ../../dist/lib/libjsdombase_s.a(BlockGrouper.o)(.text+0x98): unresolvable relocation against symbol `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostre silverburgh.meryl@gmail.com C++ 3 03-09-2006 12:14 AM
char *fred; char * fred; char *fred; any difference? Ben Pfaff C Programming 5 01-17-2004 07:37 PM
The difference between char a[6] and char *p=new char[6] ? wwj C Programming 24 11-07-2003 05:27 PM
the difference between char a[6] and char *p=new char[6] . wwj C++ 7 11-05-2003 12:59 AM



Advertisments