【问题标题】:C++ 'substitute' for structure with a flexible array memberC++“替代”具有灵活数组成员的结构
【发布时间】:2014-09-17 13:35:23
【问题描述】:

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

请注意,我只想获得 lenfree 的正确(负)偏移值;不打算访问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;
}

有效,给出相同的结果?

【问题讨论】:

  • 如果 buf 是一个灵活数组成员、长度数组或元素类型的单个成员。在实践中,它会是。但是如果你走到那一步,你不妨看看那个编译器是否接受 0 长度的数组。
  • 另一个观察结果:这几乎是但不完全是 Windows BSTR
  • 很抱歉关于演员阵容的评论,我写的时候没有正确阅读代码。 狠狠地踢自己。另外,开始喝一杯咖啡。
  • 这种(int) 转换是否有原因?

标签: c++ c arrays flexible-array-member


【解决方案1】:

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

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

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

【讨论】:

  • 好吧,我猜BSTR 是一个仅限 Windows 的东西,对吧?这对我没有帮助......
  • 经过一番思考,我想正确的解决方案是编写 autoconf 支持,它只计算 lenfree 的负偏移量,然后使用这两个常量来转换标题模板 @987654327 @ 到hdr.h,去掉标题中offsetof 的使用。
  • 另外,另一个 autoconf 宏(在使用时)可以调整 len and free` 使用的数据类型以具有适当的大小。
【解决方案2】:

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

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

【讨论】:

  • 不同编译器(从不同供应商的编译器的意义上来说)二进制级别兼容性的问题与所问的不同。
  • @Cheersandhth.-Alf 对于不同的编译器,我关心的是填充、不同类型的大小等决定。
猜你喜欢
  • 1970-01-01
  • 2020-04-13
  • 2012-11-22
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 2011-07-25
  • 2020-02-10
相关资源
最近更新 更多