3

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?

this
  • 5,229
  • 1
  • 22
  • 51
krisharav
  • 475
  • 1
  • 5
  • 12
  • 4
    Are you really forced to use c90? – this Apr 15 '14 at 19:57
  • `struct line {int length;char contents[1]};struct line x = malloc(sizeof*x + strlen(in)); x.length = strlen(in); strcpy(line.contents, in);` A bad example because you commonly 0-terminate counted strings for easier use of APIs. – Deduplicator Apr 15 '14 at 20:04
  • @self: Strictly speaking, I am not *forced* to *use*.. but I merely hit upon piece of code that did exactly as said on Question2.6 of c-faq.. (google failed me :( ) – krisharav Apr 15 '14 at 20:24
  • +1. Didn't knew that before. – haccks Apr 15 '14 at 20:27
  • 1
    @haccks And you had better forget it immediately. Zero-sized array are made unnecessary by C99's incomplete types, and they break a number of properties that should otherwise be true and that are all consequences of the fact that the size of an object is never zero. The sooner this GCC extension is forgotten, the better. – Pascal Cuoq Apr 15 '14 at 21:34
  • @PascalCuoq agreed, I just added information on C99 flexible arrays. – Shafik Yaghmour Apr 15 '14 at 21:39

2 Answers2

6

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).
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    @haccks the C FAQ is talking pre-C99 and mentions C99 at the end, please read the entry first. – Shafik Yaghmour Apr 15 '14 at 20:08
  • 1
    I particularly like the bare `-1` and `+1` in the singular size computation of that expression. – WhozCraig Apr 15 '14 at 20:09
  • @haccks as far as I can tell the gcc manual and the C FAQ are talking about the same thing. Can you explain why you do not think they are? – Shafik Yaghmour Apr 15 '14 at 20:13
  • I don't see any flexible arrays here. Answers the question for me. – this Apr 15 '14 at 20:14
  • @self.; I removed my comment. – haccks Apr 15 '14 at 20:20
  • @krisharav am I missing something or does this address your question? – Shafik Yaghmour Apr 15 '14 at 20:20
  • hmm. didn't think the title of the question would be an issue.. I simple titled it 'variable length struct' because I hit couple other questions titled 'variable length arrays' in SO which spoke about something different.. So didn't want that to be a confusion..@haccks: So yeah, this basically answers my question. (thanks @Shafik) – krisharav Apr 15 '14 at 20:22
  • @krisharav; Yes, I agreed. @Shafik; Sorry for misunderstanding. (And yes, that downvote is not mine :) ). +1 from my side. – haccks Apr 15 '14 at 20:25
1

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

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • It's too bad the Standard forbade zero-size array declarations, since many compilers would interpret them quite usefully if the zero-size-array-check code were omitted. Giving them usefully-defined would require adding some language to the Standard, but saying that a zero-sized array can be used with any subscript that would fit within the largest containing object would be better than forcing programmers to use a phony array size. – supercat Aug 11 '16 at 23:06