Search code examples
c++carraysflexible-array-member

C++ 'substitute' for structure with a flexible array member


Consider the following C99 structure, ending with a flexible array member:

struct hdr
{
  size_t len;   
  size_t free;  
  char buf[];
};

len, for example, gets accessed with an inline function (to be put into a header file) like this, having buf as its argument:

static inline size_t slen(const char *s)
{
  struct hdr *h = (struct hdr*)(s - (int)offsetof(struct hdr, buf));
  return h->len;
}

This is part of a library, to be compiled with a C compiler. However, I would like to access this library from C++; this essentially means that the corresponding header file (with proper extern "C" {...} guard) must be valid C++ code. A possible solution is to define the slen function in the source code body, avoiding inline code completely, but this is not optimal.

My idea is to define a dummy C++ structure that is valid, and that I can map somehow to hdr, e.g.

struct cpp_hdr
{
  size_t len;
  size_t free;
  char buf[1];
}

Note that I only want to get correct (negative) offset values for len and free; no access to buf is intended.

Now my question: Is there any guarantee that

static inline size_t slen(const char *s)
{
  struct cpp_hdr *h = (struct cpp_hdr*)(s - (int)offsetof(struct cpp_hdr, buf));
  return h->len;
}

works, giving the same result?


Solution

  • In the formal nothing is guaranteed, because C++ doesn't support flexible arrays: there is no such thing, no such syntax.

    In practice compilers don't do things for no direct reason. So there won't be any willy-nilly padding introduced. However, just to make that abundantly clear I would use an array size of e.g. 666 instead of 1, which works better in the more general case (e.g. a small array of 1 char might be moved into some otherwise padding area in some other struct). As a benefit, clever code for allocation won't look simple any more. So that that has to be done properly.

    All this said, it sure sounds like a 16-bit Windows BSTR, except a BSTR doesn't have that gap between the length and the string data. Consider whether this library is just someone's for no good reason reinvention of the wheel. If so, I suggest using an original wheel instead.