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