C++ 零长度数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/295027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Array of zero length
提问by bgee
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). Array 'byData' used as pointer, but why not to use pointer instead? or array of length 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?
我正在重构一些旧代码,发现很少有包含零长度数组的结构(如下)。警告当然会被 pragma 压抑,但我未能通过包含此类结构的“新”结构创建(错误 2233)。数组“byData”用作指针,但为什么不改用指针?或长度为 1 的数组?当然,没有添加任何评论来让我享受这个过程......使用这样的东西有什么原因吗?在重构这些方面有什么建议吗?
struct someData
{
int nData;
BYTE byData[0];
}
NB It's C++, Windows XP, VS 2003
NB 是 C++、Windows XP、VS 2003
采纳答案by Martin York
Yes this is a C-Hack.
To create an array of any length:
是的,这是一个 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;
}
Now you have an object of someData with an array of a specified length.
现在你有一个 someData 对象,它有一个指定长度的数组。
回答by JaredPar
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. I suggest you take a look at this post because it likely contains the answer you want.
Raymond Chen 就该主题发表了一篇出色的博客文章。我建议你看看这篇文章,因为它可能包含你想要的答案。
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.His post should still apply to your problem.
请注意,在他的帖子中,它处理大小为 1 而不是 0 的数组。这是因为零长度数组是标准中较新的条目。他的帖子应该仍然适用于你的问题。
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. Instead of a 0 length array here you should be using a length 1 array
注意:尽管 Raymond 的帖子说 0 长度数组在 C99 中是合法的,但实际上在 C99 中仍然不合法。此处不应使用长度为 0 的数组,而应使用长度为 1 的数组
回答by arul
This is an old C hack to allow a flexible sized arrays.
这是一个旧的 C hack,允许灵活大小的数组。
In C99 standard this is not neccessary as it supports the arr[] syntax.
在 C99 标准中,这不是必需的,因为它支持 arr[] 语法。
回答by Kaz
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. This means that a compiler can reject your hack right off the bat at compile time with a diagnostic message that stops the translation.
代码在做“C struct hack”是错误的,因为零长度数组的声明是违反约束的。这意味着编译器可以在编译时立即拒绝您的 hack,并提供停止翻译的诊断消息。
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. You see, sizeof
the whole structure can include padding. For instance, if we have something like this:
请注意,offsetof
即使在数组大小为零的情况下,此计算实际上也是正确的计算。你看,sizeof
整个结构可以包括填充。例如,如果我们有这样的事情:
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. 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.
struct hack
由于ul
成员的原因,很可能会填充的大小以进行对齐。如果unsigned long
是 4 字节宽,则很可能sizeof (struct hack)
是 8,而offsetof(struct hack, foo)
几乎可以肯定是 5。该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. 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.
几年前,我在内核和用户空间之间的共享内存消息传递接口中使用了 struct hack。我不想要那里的指针,因为它们只对生成消息的进程的原始地址空间有意义。软件的内核部分使用自己在不同地址的映射来查看内存,因此一切都基于偏移量计算。
回答by Mike Ruete
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. 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. No sizeof() expressions to accidentally mess up.
第一个条目在期望分配的末尾的偏移量,也是期望分配的大小。IMO 这是一种非常优雅的尺寸计算方式。可变大小数组的元素类型是什么并不重要。offsetof(或 FIELD_OFFSET 或 Windows 中的 UFIELD_OFFSET)总是以相同的方式编写。没有 sizeof() 表达式会意外搞砸。