Search code examples
arrayscgccstructflexible-array-member

Defererencing a pointer to a struct with a Flexible Array Member doesn't "copy" the FAM?


Defererencing a pointer to a struct with a Flexible Array Member (FAM) doesn't "copy" the FAM?

That seems to be the behavior, according to this program, which creates as instance of a struct with an FAM and then inspects the "binary layout" of both a pointer to the struct and a dereference of the struct.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(){

typedef struct{
  uint8_t  idim;
  uint32_t data[];
}array_t;  // https://gustedt.wordpress.com/2011/03/14/flexible-array-member/

  int64_t  x_bdim = sizeof(array_t) + sizeof(uint32_t)*0x2;
  array_t* _x     = aligned_alloc(0x1000,x_bdim);
  array_t   x     = *_x;
  uint8_t* raw;

  x.idim          = 0xff;
  x.data[0x0]     = 0x11111111;
  x.data[0x1]     = 0x22222222;

  _x->idim          = 0xff;
  _x->data[0x0]     = 0x11111111;
  _x->data[0x1]     = 0x22222222;

  printf("%'ld %'ld %'ld\n", sizeof(array_t), sizeof(array_t) + sizeof(uint32_t)*0x2, x_bdim);

  putchar(0x0a);
  raw = (uint8_t*)_x;
  for(int i=0; i<x_bdim; ++i)
    printf("%02x\n", raw[i]);

  putchar(0x0a);
  for(int i=0; i<0x2; ++i)
    printf("%08x\n", _x->data[i]);

  putchar(0x0a);
  raw = (uint8_t*)&x;
  for(int i=0; i<x_bdim; ++i)
    printf("%02x\n", raw[i]);

  putchar(0x0a);
  for(int i=0; i<0x2; ++i)
    printf("%08x\n", x.data[i]);
}

Am I missing something, or is this correct? Is the morale of the story that we shouldn't deference (pointers to) structs with a Flexible Array Member, because we only get the "header" of the struct and not the full array data?


Solution

  • That would be correct. The compiler does not know the size of the array and assumes 0 for such operations, including copy, return, assign, and compare. In effect, the flexible array is after the struct.

    GCC's prototype syntax was more obvious. They had it written as uint32_t data[0];