考虑以下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" {...}
保护)必须是有效的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;
}
工作,给出相同的结果?
答案 0 :(得分:1)
假设库是由不同的编译器编译的,则无法保证偏移量是相同的。实际上,它应该在大多数时间都有效。
如果您正在使用特定的编译器,您可以使用调试器并调整该编译器的偏移量计算并在开始时进行断言,以确保如果以后您决定转移到其他编译器,您的假设(调整)仍然成立或更新的版本。
答案 1 :(得分:1)
在形式上没有任何保证,因为C ++不支持灵活的数组:没有这样的东西,没有这样的语法。
在实践中,编译器不会直接做任何事情。所以不会引入任何不知名的填充。然而,为了使这一点非常清楚,我将使用例如数组大小。 666而不是1,在更一般的情况下更好地工作(例如,1 char
的小数组可能被移动到某些其他结构中的一些填充区域中)。作为一个好处,聪明的分配代码将不再简单。所以必须正确完成。
所有这些说,它确实听起来像一个16位Windows BSTR
,除了BSTR
长度和字符串数据之间没有这个差距。考虑这个图书馆是否只是一个人没有理由重新发明轮子。如果是这样,我建议使用原装车轮。