数组零长度

bge*_*gee 51 c++ arrays visual-c++ flexible-array-member

我正在重构一些旧的代码,并发现很少的结构包含零长度数组(如下).当然,由pragma压制的警告,但我没有通过包含这种结构的"新"结构创建(错误2233).数组'byData'用作指针,但为什么不使用指针呢?或长度为1的数组?当然,没有添加任何评论让我喜欢这个过程...任何使用这种东西的原因?重构那些的任何建议?

struct someData
{
   int nData;
   BYTE byData[0];
}
Run Code Online (Sandbox Code Playgroud)

NB它是C++,Windows XP,VS 2003

Mar*_*ork 34

是的,这是一个C-Hack.
要创建任何长度的数组:

struct someData* mallocSomeData(int size)
{
    struct someData*  result = (struct someData*)malloc(sizeof(struct someData) + size * sizeof(BYTE));
    if (result)
    {    result->nData = size;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

现在你有一个someData的对象,它有一个指定长度的数组.

  • @unwind:不能为此使用new。整个问题是,这是C-Hack,在C ++中不是必需的(因为我们有更好的方法可以做到)。我也很确定零长度数组在C ++中是非法的(至少是C ++ 03,不确定是否在C ++ 11中更新了)。 (2认同)
  • 除非您的计算已关闭(通常情况下)。根据数组中对象的类型,编译器需要施加某些对齐规则,并且汇总成员的大小可能无法产生正确的大小。而是使用[offsetof](http://en.cppreference.com/w/cpp/types/offsetof)宏来使编译器计算正确的结果。(注意:假设BYTE被定义为某些char变体,这对BYTE来说不是问题。) (2认同)

Jar*_*Par 25

遗憾的是,有几个原因可以在结构的末尾声明零长度数组.它本质上使您能够从API返回可变长度结构.

Raymond Chen在这个主题上写了一篇很棒的博文.我建议你看看这篇文章,因为它可能包含你想要的答案.

请注意,在他的帖子中,它处理的是大小为1而不是0的数组.这是因为零长度数组是更新的标准入口. 他的帖子应该仍适用于你的问题.

http://blogs.msdn.com/oldnewthing/archive/2004/08/26/220873.aspx

编辑

注意:尽管Raymond的帖子说0长度数组在C99中是合法的,但事实上它们在C99中仍然不合法.这里应该使用长度为1的数组,而不是0长度数组

  • "*就是这种情况,因为零长度阵列是最近进入标准的.*"哪个标准?C++ 11仍然不允许0长度数组(§8.3.4/ 1),以及C99(§6.7.5.2/ 1). (2认同)

aru*_*rul 22

这是一个旧的C hack,允许灵活大小的阵列.

在C99标准中,这不是必需的,因为它支持arr []语法.

  • 如果不解决注释的一般事实,... MS VC v9编译器支持arr []语法. (6认同)
  • 遗憾的是,在C99支持方面,Visual Studio非常差.:( (3认同)

Kaz*_*Kaz 9

你对"为什么不使用1号阵列"的直觉就是现场.

代码执行"C struct hack"错误,因为零长度数组的声明是违反约束的.这意味着编译器可以在编译时立即拒绝您的黑客攻击,并使用停止转换的诊断消息.

如果我们想要进行黑客攻击,我们必须将它偷偷摸摸地通过编译器.

执行"C struct hack"(与C语言兼容,可以追溯到1989 ANSI C,可能更早)的正确方法是使用大小为1的完全有效的数组:

struct someData
{
   int nData;
   unsigned char byData[1];
}
Run Code Online (Sandbox Code Playgroud)

而且,使用以下方法计算sizeof struct someData之前部件的尺寸byData:

offsetof(struct someData, byData);
Run Code Online (Sandbox Code Playgroud)

struct someData为42字节分配空间byData,我们将使用:

struct someData *psd = (struct someData *) malloc(offsetof(struct someData, byData) + 42);
Run Code Online (Sandbox Code Playgroud)

请注意,offsetof即使在数组大小为零的情况下,此计算实际上也是正确的计算.你看,sizeof整个结构可以包括填充.例如,如果我们有这样的事情:

struct hack {
  unsigned long ul;
  char c;
  char foo[0]; /* assuming our compiler accepts this nonsense */
};
Run Code Online (Sandbox Code Playgroud)

struct hack由于该ul构件,很可能填充尺寸以进行对齐.如果unsigned long是四个字节宽,则很可能sizeof (struct hack)是8,而offsetof(struct hack, foo)几乎可以肯定是5.该offsetof方法是在数组之前获得结构的前一部分的准确大小的方法.

这就是重构代码的方法:使其符合经典,高度可移植的struct hack.

为什么不使用指针?因为指针占用额外的空间并且必须初始化.

还有其他很好的理由不使用指针,即指针需要一个地址空间才能有意义.struct hack是可外部化的:也就是说,在某些情况下,这样的布局符合外部存储,例如文件,数据包或共享内存区域,在这些区域中,您不需要指针,因为它们没有意义.

几年前,我在内核和用户空间之间传递接口的共享内存消息中使用了struct hack.我不想在那里使用指针,因为它们只对生成消息的进程的原始地址空间有意义.软件的内核部分使用自己在不同地址的映射来查看内存,因此所有内容都基于偏移计算.