0

I came across definition of a struct that looked something like this in the linux kernel sources (net/ipv4/fib_trie.c)-

 
struct key_vector {
    t_key key;
    unsigned char pos;      /* 2log(KEYLENGTH) bits needed */
    unsigned char bits;     /* 2log(KEYLENGTH) bits needed */
    unsigned char slen;
    union {
        /* This list pointer if valid if (pos | bits) == 0 (LEAF) */
        struct hlist_head leaf;
        /* This array is valid if (pos | bits) > 0 (TNODE) */
        struct key_vector __rcu *tnode[0];
    };
};

What does above definition of tnode mean? I wrote a sample code to understand and print that looks like -


struct s {
    union {
        int i;
        int *pi[0];
    };
};

int main()
{
    struct s s1;
    s1.i = 0x12345678;

    printf("sizeof(s1): %lu, s1.i: %x, s1.pi: %p, s1.*pi: %p\n", sizeof(s1), s1.i, s1.pi[0], s1.pi);
}

The output of which is -

sizeof(s1): 8, s1.i: 12345678, s1.pi: 0x7ffc12345678, s1.*pi: 0x7ffc2824add0

I am not entirely sure I understand this.

gabhijit
  • 3,345
  • 2
  • 23
  • 36

2 Answers2

4

This is a common practice known as "the struct hack" or flexible array member. When allocating memory for the struct, you add additional space. Then that extra space can be accessed using the array member at the end of the struct. Since C99, you can omit the size entirely.

luser droog
  • 18,988
  • 3
  • 53
  • 105
-1

Prior to the ratification of C89, many compilers would interpret a declaration like someType member[someConst]; within a structure as advancing the "next item offset" to a multiple of someType's alignment requirement, associating symbol member with that offset, interpreting someConst as an unsigned number, and then advancing the "next member offset" by someConst * sizeof someType. They would behave in this fashion without regard for whether someConst was zero. Because some programs relied upon compilers processing zero-length array declarations this way, but some members of the Committee didn't want to require that all compilers support them, the authors of the Standard opted to say that implementations may support zero-sized arrays or not, at their leisure, provided that when fed any program that exploits zero-sized arrays they issue at least one diagnostic (which programmers could then ignore at their leisure when using an implementation that usefully supported the construct).

supercat
  • 77,689
  • 9
  • 166
  • 211