在C99中,您可以声明结构的灵活数组成员:
struct blah
{
int foo[];
};
然而,当有人在这里工作时尝试使用C ++中的clang编译一些代码时,该语法不起作用。 (它一直在与MSVC合作。)我们必须将其转换为:
struct blah
{
int foo[0];
};
通过C ++标准,我发现根本没有提到灵活的成员数组;我一直认为[0]
是一个无效的声明,但显然对于一个灵活的成员数组它是有效的。灵活的成员数组在C ++中实际上是否有效?如果是,请使用正确的声明[]
或[0]
?
答案 0 :(得分:21)
C ++最初是在1998年标准化的,所以它早于将灵活的数组成员添加到C(这在C99中是新的)。 2003年有一个C ++的更正,但没有添加任何相关的新功能。 C ++的下一个版本(C ++ 0x)仍在开发中,似乎没有添加灵活的数组成员。
答案 1 :(得分:18)
C ++在结构末尾不支持C99灵活数组成员,使用空索引表示法或0
索引表示法(禁止特定于供应商的扩展):
struct blah
{
int count;
int foo[]; // not valid C++
};
struct blah
{
int count;
int foo[0]; // also not valid C++
};
据我所知,C ++ 0x也不会添加它。
但是,如果将数组的大小设置为1个元素:
struct blah
{
int count;
int foo[1];
};
事情是有效的,并且工作得很好。您可以使用不太可能出现一个错误的表达式来分配适当的内存:
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)
}
因此它可以在C90,C99和C ++之间移植,并且与C99的灵活阵列成员一样好。
Raymond Chen写了一篇很好的文章:Why do some structures end with an array of size 1?
注意:在Raymond Chen的文章中,在一个例子中有一个错误/错误来初始化'灵活的'阵列。它应该是:
for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
TokenGroups->Groups[Index] = ...;
}
答案 2 :(得分:3)
第二个不包含元素,而是指向blah
之后。所以如果你有这样的结构:
struct something
{
int a, b;
int c[0];
};
你可以这样做:
struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int));
val->a = 1;
val->b = 2;
val->c[0] = 3;
在这种情况下,c
将表现为具有5 int
s的数组,但数组中的数据将位于something
结构之后。
我正在处理的产品使用它作为一个大小的字符串:
struct String
{
unsigned int allocated;
unsigned int size;
char data[0];
};
由于支持的体系结构,这将消耗8个字节加上allocated
。
当然所有这些都是C,但g ++例如毫无障碍地接受它。
答案 3 :(得分:1)
如果可以将应用程序限制为仅需要几个已知大小,则可以使用模板有效地实现灵活的数组。
template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
T flex_[SZ];
};
答案 4 :(得分:1)
一项提案正在制定中,可能会纳入将来的C ++版本。
有关详细信息,请参见numpy.where
(该提案是相当新的,因此可能会有所更改)
答案 5 :(得分:0)
如果你只想要
struct blah { int foo[]; };
那么你根本不需要这个结构,只需处理一个malloc&ed / new&#39; ed int数组。
如果您在开头有一些成员:
struct blah { char a,b; /*int foo[]; //not valid in C++*/ };
然后在C ++中,我想你可以用foo
成员函数替换foo
:
struct blah { alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); } };
使用示例:
#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;
}
答案 6 :(得分:0)
我面临一个同样的问题,即声明一个可用于C ++代码的灵活数组成员。通过查看glibc
标头,我发现灵活数组成员有一些用法,例如在struct inotify
中声明如下(省略注释和一些不相关的成员):
struct inotify_event
{
//Some members
char name __flexarr;
};
__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
我对MSVC
编译器并不熟悉,但是您可能不得不根据MSVC
的版本再添加一个条件宏。
答案 7 :(得分:0)
标准 C++ 不支持灵活数组成员,但是 clang 文档说。
“除了此处列出的语言扩展之外,Clang 还旨在支持广泛的 GCC 扩展。”
C++ 的 gcc 文档说。
“GNU 编译器为 C++ 语言提供了这些扩展(您也可以在 C++ 程序中使用大多数 C 语言扩展)。”
C 文档的 gcc 文档支持零长度数组。
答案 8 :(得分:0)
灵活数组还不是 C++ 标准的一部分。这就是 int foo[]
或 int foo[0]
可能无法编译的原因。虽然有一个 proposal 正在讨论中,但它尚未被 C++ (C++2b) 的最新修订版接受。
然而,几乎所有现代编译器都通过编译器扩展支持它。
问题是,如果您在最高警告级别 (-Wall --pedantic
) 下使用此扩展程序,可能会导致警告。
对此的解决方法是使用包含一个元素的数组并进行越界访问。虽然这个解决方案是规范(dcl.array 和 expr.add)的 UB,但大多数编译器都会生成有效的代码,甚至 clang -fsanitize=undefined
对它也很满意:
#include <new>
#include <type_traits>
struct A {
int a[1];
};
int main()
{
using storage_type = std::aligned_storage_t<1024, alignof(A)>;
static storage_type memory;
A *ptr_a = new (&memory) A;
ptr_a->a[2] = 42;
return ptr_a->a[2];
}
答案 9 :(得分:-4)
更好的解决方案是将其声明为指针:
struct blah
{
int* foo;
};
或者更好的是,将其声明为std::vector
:
struct blah
{
std::vector<int> foo;
};