灵活数组成员在 C++ 中有效吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4412749/
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
Are flexible array members valid in C++?
提问by MSN
In C99, you can declare a flexible array member of a struct as such:
在 C99 中,您可以像这样声明结构的灵活数组成员:
struct blah
{
int foo[];
};
However, when someone here at work tried to compile some code using clang in C++, that syntax did not work. (It had been working with MSVC.) We had to convert it to:
但是,当工作中的某个人尝试在 C++ 中使用 clang 编译一些代码时,该语法不起作用。(它一直在与 MSVC 一起工作。)我们必须将其转换为:
struct blah
{
int foo[0];
};
Looking through the C++ standard, I found no reference to flexible member arrays at all; I always thought [0]
was an invalid declaration, but apparently for a flexible member array it is valid. Are flexible member arrays actually valid in C++? If so, is the correct declaration []
or [0]
?
查看 C++ 标准,我发现根本没有提到灵活的成员数组;我一直认为[0]
是无效声明,但显然对于灵活的成员数组它是有效的。灵活的成员数组在 C++ 中实际上有效吗?如果是这样,是正确的声明[]
还是[0]
?
采纳答案by Martin v. L?wis
C++ was first standardized in 1998, so it predates the addition of flexible array members to C (which was new in C99). There was a corrigendum to C++ in 2003, but that didn't add any relevant new features. The next revision of C++ (C++0x) is still under development, and it seems flexible array members aren't added to it.
C++ 于 1998 年首次标准化,因此它早于向 C(C99 中的新成员)添加灵活数组成员。2003 年对 C++ 进行了更正,但没有添加任何相关的新功能。C++ (C++0x) 的下一个修订版仍在开发中,似乎没有添加灵活的数组成员。
回答by Michael Burr
C++ doesn't support C99 flexible array members at the end of structures, either using an empty index notation or a 0
index notation (barring vendor-specific extensions):
C++ 不支持结构末尾的 C99 灵活数组成员,无论是使用空索引符号还是0
索引符号(除非供应商特定的扩展):
struct blah
{
int count;
int foo[]; // not valid C++
};
struct blah
{
int count;
int foo[0]; // also not valid C++
};
As far as I know, C++0x will not add this, either.
据我所知,C++0x 也不会添加这个。
However, if you size the array to 1 element:
但是,如果将数组大小调整为 1 个元素:
struct blah
{
int count;
int foo[1];
};
things are valid, and work quite well. You can allocate the appropriate memory with an expression that is unlikely to have off-by-one errors:
事情是有效的,并且工作得很好。您可以使用不太可能出现非一错误的表达式分配适当的内存:
struct blah* p = (struct blah*) malloc( offsetof(struct blah, foo[desired_number_of_elements]);
if (p) {
p->count = desired_number_of_elements;
// initialize your p->foo[] array however appropriate - it has `count`
// elements (indexable from 0 to count-1)
}
So it's portable between C90, C99 and C++ and works just as well as C99's flexible array members.
因此它可以在 C90、C99 和 C++ 之间移植,并且与 C99 的灵活数组成员一样有效。
Raymond Chen did a nice writeup about this: Why do some structures end with an array of size 1?
Raymond Chen 对此写了一篇很好的文章:为什么有些结构以大小为 1 的数组结尾?
Note: In Raymond Chen's article, there's a typo/bug in an example initializing the 'flexible' array. It should read:
注意:在 Raymond Chen 的文章中,初始化“flexible”数组的示例中存在拼写错误/错误。它应该是:
for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
TokenGroups->Groups[Index] = ...;
}
回答by terminus
The second one will not contain elements but rather will point right after blah
. So if you have a structure like this:
第二个将不包含元素,而是将指向blah
. 所以如果你有这样的结构:
struct something
{
int a, b;
int c[0];
};
you can do things like this:
你可以做这样的事情:
struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int));
val->a = 1;
val->b = 2;
val->c[0] = 3;
In this case c
will behave as an array with 5 int
s but the data in the array will be after the something
structure.
在这种情况下,c
将表现为具有 5int
秒的数组,但数组中的数据将在something
结构之后。
The product I'm working on uses this as a sized string:
我正在开发的产品使用它作为一个大小的字符串:
struct String
{
unsigned int allocated;
unsigned int size;
char data[0];
};
Because of the supported architectures this will consume 8 bytes plus allocated
.
由于支持的架构,这将消耗 8 个字节加上allocated
.
Of course all this is C but g++ for example accepts it without a hitch.
当然,所有这些都是 C 语言,但例如 g++ 可以毫无障碍地接受它。
回答by jxh
If you can restrict your application to only require a few known sizes, then you can effectively achieve a flexible array with a template.
如果您可以将您的应用程序限制为仅需要几个已知大小,那么您可以使用模板有效地实现灵活的数组。
template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
T flex_[SZ];
};
回答by pqnet
A proposal is underway, and might make into some future C++ version. See https://thephd.github.io/vendor/future_cxx/papers/d1039.htmlfor details (the proposal is fairly new, so it's subject to changes)
一项提案正在进行中,可能会成为未来的 C++ 版本。详情请参阅https://thephd.github.io/vendor/future_cxx/papers/d1039.html(该提案相当新,因此可能会发生变化)
回答by PSkocik
If you only want
如果你只想
struct blah { int foo[]; };
then you don't need the struct at all an you can simply deal with a malloc'ed/new'ed int array.
那么你根本不需要结构体,你可以简单地处理一个 malloc'ed/new'ed int 数组。
If you have some members at the beginning:
如果一开始有一些成员:
struct blah { char a,b; /*int foo[]; //not valid in C++*/ };
then in C++, I suppose you could replace foo
with a foo
member function:
然后在 C++ 中,我想你可以foo
用一个foo
成员函数替换:
struct blah { alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); } };
Example use:
使用示例:
#include <stdlib.h>
struct blah {
alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); }
};
int main()
{
blah *b = (blah*)malloc(sizeof(blah)+10*sizeof(int));
if(!b) return 1;
b->foo()[1]=1;
}
回答by St.Antario
I faced the same problem to declare a flexible array member which can be used from C++ code. By looking through glibc
headers I found that there are some usages of flexible array members, e.g. in struct inotify
which is declared as follows (comments and some unrelated members omitted):
我面临同样的问题来声明一个可以从 C++ 代码中使用的灵活数组成员。通过查看glibc
标题,我发现有一些灵活数组成员的用法,例如,struct inotify
其中声明如下(省略了注释和一些不相关的成员):
struct inotify_event
{
//Some members
char name __flexarr;
};
The __flexarr
macro, in turn is defined as
的__flexarr
宏又被定义为
/* Support for flexible arrays.
Headers that should use flexible arrays only if they're "real"
(e.g. only if they won't affect sizeof()) should test
#if __glibc_c99_flexarr_available. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif __GNUC_PREREQ (2,97)
/* GCC 2.97 supports C99 flexible array members as an extension,
even when in C89 mode or compiling C++ (any version). */
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif defined __GNUC__
/* Pre-2.97 GCC did not support C99 flexible arrays but did have
an equivalent extension with slightly different notation. */
# define __flexarr [0]
# define __glibc_c99_flexarr_available 1
#else
/* Some other non-C99 compiler. Approximate with [1]. */
# define __flexarr [1]
# define __glibc_c99_flexarr_available 0
#endif
I'm not familar with MSVC
compiler, but probably you'd have to add one more conditional macro depending on MSVC
version.
我不熟悉MSVC
编译器,但可能您必须根据MSVC
版本再添加一个条件宏。
回答by Zac Howland
The better solution is to declare it as a pointer:
更好的解决方案是将其声明为指针:
struct blah
{
int* foo;
};
Or better yet, to declare it as a std::vector
:
或者更好的是,将其声明为std::vector
:
struct blah
{
std::vector<int> foo;
};