当前位置:  开发笔记 > 编程语言 > 正文

数组零长度

如何解决《数组零长度》经验,为你挑选了4个好方法。

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

struct someData
{
   int nData;
   BYTE byData[0];
}

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



1> Martin York..:

是的,这是一个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;
}

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


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

2> JaredPar..:

遗憾的是,有几个原因可以在结构的末尾声明零长度数组.它本质上使您能够从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).

3> arul..:

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

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


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

4> Kaz..:

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

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

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

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

struct someData
{
   int nData;
   unsigned char byData[1];
}

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

offsetof(struct someData, byData);

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

struct someData *psd = (struct someData *) malloc(offsetof(struct someData, byData) + 42);

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

struct hack {
  unsigned long ul;
  char c;
  char foo[0]; /* assuming our compiler accepts this nonsense */
};

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

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

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

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

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

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有