zero length array in C

Declaring Zero length array in place of normal pointers is a common programming practice in networking jargon where we have to implement header of a payload to be passed across network. In this article, we will discuss how we can implement variable length payload using the concept of zero sized array.


* Declaration of zero length array

 struct payload {
         int length;
         char data[0];
 };

    The above declaration creates a structure for a network payload, for which we can define the length of the payload in field "length" and the variable length data would go in field "data".


* How is this different from pointers ?   

struct payload {
        int length;
        char *data;
 };

    The above declaration seems similar to what we had earlier and looks like well suited for the payload data-structure. However, there is a subtle difference when we consider sending data over network. To use this structure as a payload, let us allocate the memory first and see why this is not a good choice for network payloads.

    struct payload *p = (struct payload *)malloc(sizeof(struct payload));
    p->data = (char*)malloc(sizeof(char) * payload_len);
    p->length = payload_len;
    p->data = //assign data.

    Memory allocation will return different memory address from Heap for base address(p) and data(p->data) and thus is not aligned with the base address of the payload structure. To send this structure over network, we have to start from the base address of the given structure and start copying the required number of bytes one by one over the network. But, the base address of the structure is not at the same memory chunk as that of the data. Hence, simple byte by byte copying of the payload to the network is not possible in this case.

    This is where the zero sized array comes into picture. Due to its declaration syntax, the memory address of the field data is properly aligned with the base address of the payload structure (data is at offset of 4 bytes from the base address). This is how we allocate memory for this:

    struct payload *p = (struct payload *)malloc(sizeof(struct payload) + payload_len*sizeof(char));
    p->length = payload_len;
    p->data = //assign data.

    In this case we are allocating the whole memory in one big chunk and also it is easily accessible by adding offset of '4' (considering size of int as 4 bytes) to the base address allocated in above malloc() call. Hence, while sending the data over the network, we can simply send the base address of the packet with properly filling up the length of upcoming data. And at the receiving end we can very easily convert back the data easily from this payload structure.


* Few important facts:
    Zero length arrays are allowed in GNU C. The sizeof() operator doesnt take into account the size of zero length array. The best use case for this as already explained is the payload structure widely used in networking. One more example :   

struct payload {
         int protocol;
         int flags;
             :
             :
         int size;
         struct data payload_data[0];  // data can itself be another structure or another structure with variable length arrays
     }

    In ISO C90 it is required to declare data field as 'data[1]'. However, ISO C99 provides concept of size-less array also known as flexible-array member e.g. 'char data[]'.

    For reference on support by GCC you can check this GCC manual.


- Pankaj Pal
Happy Programming !!

comments powered by Disqus