考虑以下C99结构,以灵活的数组成员结束:
struct hdr
{
size_t len;
size_t free;
char buf[];
};
例如,len使用内联函数(将被放入头文件)访问,像这样,将buf作为其参数:
static inline size_t slen(const char *s)
{
struct hdr *h = (struct hdr*)(s - (int)offsetof(struct hdr, buf));
return h->len;
}
这是库的一部分,用C编译器编译.但是,我想从C访问这个库;这实际上意味着相应的头文件(具有适当的extern“C”{…} guard)必须是有效的C代码.一种可能的解决方案是在源代码体中定义slen函数,完全避免内联代码,但这不是最优的.
我的想法是定义一个有效的虚拟C结构,并且我可以某种方式映射到hdr,例如
struct cpp_hdr
{
size_t len;
size_t free;
char buf[1];
}
请注意,我只想获得len和free的正确(负)偏移值;不打算访问buf.
现在我的问题是:有任何保证
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;
}
工作,给出相同的结果?
最佳答案 在形式上没有任何保证,因为C不支持灵活的数组:没有这样的东西,没有这样的语法.
在实践中,编译器不会直接做任何事情.所以不会引入任何不知名的填充.然而,为了使这一点非常清楚,我将使用例如数组大小. 666而不是1,它在更一般的情况下工作得更好(例如,1个字符的小数组可能被移动到某些其他结构中的某个填充区域中).作为一个好处,聪明的分配代码将不再简单.所以必须正确完成.
所有这些说,它确实听起来像一个16位Windows BSTR,除了BSTR在长度和字符串数据之间没有这个差距.考虑这个图书馆是否只是一个人没有理由重新发明轮子.如果是这样,我建议改用原车轮.