5

考虑以下以灵活数组成员结尾的 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];
}

请注意,我只想为lenand获得正确的(负)偏移值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;
}

工作,给出相同的结果?

4

2 回答 2

3

在形式上没有任何保证,因为 C++ 不支持灵活的数组:没有这样的东西,没有这样的语法。

在实践中,编译器不会无缘无故地做事。所以不会引入任何任性的填充。但是,为了更清楚地说明这一点,我将使用例如 666 而不是 1 的数组大小,这在更一般的情况下效果更好(例如,一个 1 的小数组char可能会移动到其他结构中的其他填充区域)。作为一个好处,聪明的分配代码看起来不再简单。所以这必须正确地完成。

综上所述,它听起来确实像一个 16 位 Windows BSTR,除了 aBSTR在长度和字符串数据之间没有那个差距。考虑一下这个库是否只是某人无缘无故地重新发明了轮子。如果是这样,我建议改用原装轮子。

于 2014-09-17T14:00:51.767 回答
2

假设库是由不同的编译器编译的,则不能保证偏移量相同。实际上,它应该在大部分时间都有效。

如果您正在使用特定的编译器,您可以使用调试器并调整该编译器的偏移量计算,并在开始时做出断言,以确保您的假设(调整)在以后决定迁移到不同的编译器或更新版本时仍然成立.

于 2014-09-17T13:44:43.863 回答