简体   繁体   English

零长度数组

[英]Array of zero length

I am working on refactoring some old code and have found few structs containing zero length arrays (below). 我正在重构一些旧代码,发现很少包含零长度数组的结构(如下)。 Warnings depressed by pragma, of course, but I've failed to create by "new" structures containing such structures (error 2233). 当然,编译指示会压制警告,但是我无法通过包含此类结构的“新”结构来创建(错误2233)。 Array 'byData' used as pointer, but why not to use pointer instead? 数组“ byData”用作指针,但是为什么不使用指针呢? or array of length 1? 或长度为1的数组? And of course, no comments were added to make me enjoy the process... Any causes to use such thing? 当然,没有添加任何注释使我喜欢此过程...使用此类东西的任何原因? Any advice in refactoring those? 在重构这些方面有什么建议吗?

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

NB It's C++, Windows XP, VS 2003 注意:这是C ++,Windows XP,VS 2003

Yes this is a C-Hack. 是的,这是C-Hack。
To create an array of any length: 要创建任意长度的数组:

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

Now you have an object of someData with an array of a specified length. 现在,您有了一个具有指定长度的数组的someData对象。

There are, unfortunately, several reasons why you would declare a zero length array at the end of a structure. 不幸的是,有几个原因导致您在结构末尾声明零长度数组。 It essentially gives you the ability to have a variable length structure returned from an API. 从本质上讲,它使您能够具有从API返回的可变长度结构。

Raymond Chen did an excellent blog post on the subject. 雷蒙德·陈(Raymond Chen)在该主题上发表了出色的博客文章。 I suggest you take a look at this post because it likely contains the answer you want. 我建议您看一下这篇文章,因为它可能包含您想要的答案。

Note in his post, it deals with arrays of size 1 instead of 0. This is the case because zero length arrays are a more recent entry into the standards. 请注意,在他的文章中,它处理的是大小为1而不是0的数组。 之所以如此,是因为零长度数组是标准中更新的条目。 His post should still apply to your problem. 他的帖子仍然适用于您的问题。

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

EDIT 编辑

Note: Even though Raymond's post says 0 length arrays are legal in C99 they are in fact still not legal in C99. 注意:即使Raymond的帖子说0长度数组在C99中是合法的,但实际上在C99中仍然不合法。 Instead of a 0 length array here you should be using a length 1 array 您应该使用长度为1的数组,而不是长度为0的数组

This is an old C hack to allow a flexible sized arrays. 这是一个古老的C语言,可允许使用大小灵活的数组。

In C99 standard this is not neccessary as it supports the arr[] syntax. 在C99标准中,这不是必需的,因为它支持arr []语法。

Your intution about "why not use an array of size 1" is spot on. 您对“为什么不使用大小为1的数组”的直觉很明显。

The code is doing the "C struct hack" wrong, because declarations of zero length arrays are a constraint violation. 代码做错了“ C struct hack”,因为零长度数组的声明违反了约束。 This means that a compiler can reject your hack right off the bat at compile time with a diagnostic message that stops the translation. 这意味着编译器可以在编译时立即通过一条诊断消息来停止您的黑客攻击,该消息会停止翻译。

If we want to perpetrate a hack, we must sneak it past the compiler. 如果要进行黑客入侵,则必须将其通过编译器。

The right way to do the "C struct hack" (which is compatible with C dialects going back to 1989 ANSI C, and probably much earlier) is to use a perfectly valid array of size 1: 进行“ C struct hack”(与自1989年ANSI C以来的C语言方言兼容,并且可能更早)的正确方法是使用大小为1的完全有效的数组:

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

Moreover, instead of sizeof struct someData , the size of the part before byData is calculated using: 此外,代替sizeof struct someData ,使用以下方法计算byData之前的部分的大小:

offsetof(struct someData, byData);

To allocate a struct someData with space for 42 bytes in byData , we would then use: 要分配struct someData与42个字节的空间byData ,我们会再使用:

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

Note that this offsetof calculation is in fact the correct calculation even in the case of the array size being zero. 请注意,即使在数组大小为零的情况下,此offsetof计算实际上也是正确的计算。 You see, sizeof the whole structure can include padding. 您会看到,整个结构的sizeof可以包含填充。 For instance, if we have something like this: 例如,如果我们有这样的事情:

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

The size of struct hack is quite possibly padded for alignment because of the ul member. 由于ul成员, struct hack的大小很可能被填充以进行对齐。 If unsigned long is four bytes wide, then quite possibly sizeof (struct hack) is 8, whereas offsetof(struct hack, foo) is almost certainly 5. The offsetof method is the way to get the accurate size of the preceding part of the struct just before the array. 如果unsigned long是四个字节宽,则sizeof (struct hack)很可能为8,而offsetof(struct hack, foo)几乎可以确定为offsetof方法是获取结构前面部分准确大小的方法。就在数组之前

So that would be the way to refactor the code: make it conform to the classic, highly portable struct hack. 这样便可以重构代码:使其符合经典的,高度可移植的struct hack。

Why not use a pointer? 为什么不使用指针? Because a pointer occupies extra space and has to be initialized. 因为指针占用额外的空间,所以必须进行初始化。

There are other good reasons not to use a pointer, namely that a pointer requires an address space in order to be meaningful. 还有其他不使用指针的充分理由,即,指针需要一个地址空间才能有意义。 The struct hack is externalizeable: that is to say, there are situations in which such a layout conforms to external storage such as areas of files, packets or shared memory, in which you do not want pointers because they are not meaningful. struct hack是可外部化的:也就是说,在某些情况下,此类布局与外部存储(例如文件,数据包或共享内存)相符,在这种情况下,您不需要指针,因为它们没有意义。

Several years ago, I used the struct hack in a shared memory message passing interface between kernel and user space. 几年前,我在内核和用户空间之间的共享内存消息传递接口中使用了struct hack。 I didn't want pointers there, because they would have been meaningful only to the original address space of the process generating a message. 我不希望指针在那里,因为它们只会对生成消息的进程的原始地址空间有意义。 The kernel part of the software had a view to the memory using its own mapping at a different address, and so everything was based on offset calculations. 该软件的内核部分使用其在不同地址的映射来查看内存,因此所有内容均基于偏移量计算。

It's worth pointing out IMO the best way to do the size calculation, which is used in the Raymond Chen article linked above. 值得指出的是,IMO是进行尺寸计算的最佳方法,该方法已在上面链接的Raymond Chen文章中使用。

struct foo
{
    size_t count;
    int data[1];
}

size_t foo_size_from_count(size_t count)
{
    return offsetof(foo, data[count]);
}

The offset of the first entry off the end of desired allocation, is also the size of the desired allocation. 第一个条目偏离所需分配结束的偏移量也是所需分配的大小。 IMO it's an extremely elegant way of doing the size calculation. IMO,这是一种非常优雅的尺寸计算方法。 It does not matter what the element type of the variable size array is. 可变大小数组的元素类型是什么都没有关系。 The offsetof (or FIELD_OFFSET or UFIELD_OFFSET in Windows) is always written the same way. offsetof(或Windows中的FIELD_OFFSET或UFIELD_OFFSET)始终以相同的方式编写。 No sizeof() expressions to accidentally mess up. 没有sizeof()表达式会导致混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM