Question

Zero-length arrays are allowed in GNU C. and can be initialized thus

struct line {
       int length;
       char contents[0];
     };

     struct line *thisline = (struct line *)
       malloc (sizeof (struct line) + this_length);
     thisline->length = this_length;

Note: I am referring to this page here: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html (provides a basic intro to variable length structures in C)

It goes on to say: "In ISO C90, you would have to give contents a length of 1, which means either you waste space or complicate the argument to malloc."

What does that mean? Could someone provide an example of how you can initialize variable length structs in C90 to aid understanding?

Was it helpful?

Solution

If you really have to use c90 then the C FAQ has this covered in Question 2.6 :

struct name {
int namelen;
char namestr[1];
};

struct name *ret =
    malloc(sizeof(struct name)-1 + strlen(newname)+1);
            /* -1 for initial [1]; +1 for \0 */

Although the FAQ does say:

It's not clear if it's legal or portable, but it is rather popular. An implementation of the technique might look something like this.

Although the gcc document basically says they support it, in C99 as the FAQ says they added flexible array members, which I cover in this answer which is covered in section 6.7.2.1 Structure and union specifiers and has the following example, which unlike the C90 example does not require special math to account for the size of the array:

EXAMPLE After the declaration:

   struct s { int n; double d[]; };

the structure struct s has a flexible array member d. A typical way to use this
is:

    int m = /* some value */;
    struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));

and assuming that the call to malloc succeeds, the object pointed to by p
behaves, for most purposes, as if p had been declared as:

     struct { int n; double d[m]; } *p;

(there are circumstances in which this equivalence is broken; in particular, the
 offsets of member d might not be the same).

OTHER TIPS

The comment concerning complication of size computation deals with the fundamental differentiation of C with vs. without flexible array member support (i.e. C90 vs. C99). When using a singular element array within your struct, the element contributes to the sizeof() the type. Therefore the flexible size computation used for real flexible arrays won't work:

In C90:

struct name 
{
    int namelen;
    char namestr[1]; // contributes 1 + potential padding to sizeof(name)
}; 

// using "the one" [1] as our terminator
struct name *p = malloc(sizeof(name) + strlen(str)) 

whereas in C99 with a flexible member

struct name 
{
    int namelen;
    char namestr[]; // contributes no definitive value to sizeof(name)
}; 

// specifying space for our terminator, since [] gives us nothing.
struct name *p = malloc(sizeof(name) + strlen(str) + 1)

If you're wondering about that comment concerning no contribution to space,

C99 §6.7.2.1 Structures and Union Specificers

18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. ....

C90 makes no such niceties, and as such the structure must be allocated differently (and arguably in a manner that is unspecified, if not outright undefined).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top