灵活数组成员在 C++ 中有效吗?
在 C99 中,您可以像这样声明结构的灵活数组成员:
struct blah
{
int foo[];
};
但是,当有人在工作中尝试使用 C++ 中的 clang 编译一些代码时,该语法不起作用。 (它一直在与 MSVC 一起使用。)我们必须将其转换为:
struct blah
{
int foo[0];
};
纵观 C++ 标准,我发现根本没有对灵活成员数组的引用;我一直认为 [0]
是一个无效的声明,但显然对于灵活的成员数组来说它是有效的。灵活成员数组在 C++ 中实际上有效吗?如果是这样,正确的声明是 []
还是 [0]
?
In C99, you can declare a flexible array member of a struct as such:
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:
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]
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
C++ 于 1998 年首次标准化,因此它早于向 C 添加灵活数组成员(这是 C99 中的新增功能)。 2003 年对 C++ 进行了勘误,但没有添加任何相关的新功能。 C++ (C++2b) 的下一个修订版仍在开发中,并且似乎仍然没有添加灵活的数组成员。
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++2b) is still under development, and it seems flexible array members still aren't added to it.
C++ 不支持结构末尾的 C99 灵活数组成员,无论是使用空索引表示法还是
0
索引表示法(禁止供应商特定的扩展):据我所知,C++ 0x 也不会添加这个。
但是,如果将数组大小设置为 1 个元素:
代码将编译并运行得很好,但从技术上讲,这是未定义的行为。您可以使用不太可能出现相差一错误的表达式来分配适当的内存:
因此它可以在 C90、C99 和 C++ 之间移植,并且与 C99 灵活的数组成员一样工作。
Raymond Chen 对此做了一篇很好的文章: 为什么某些结构以数组结尾size 1?
注意:在 Raymond Chen 的文章中,初始化“灵活”数组的示例中存在拼写错误/错误。它应该是:
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):As far as I know, C++0x will not add this, either.
However, if you size the array to 1 element:
the code will compile, and work quite well, but it is technically undefined behavior. You can allocate the appropriate memory with an expression that is unlikely to have off-by-one errors:
So it's portable between C90, C99 and C++ and works just as well as C99's flexible array members.
Raymond Chen did a nice writeup about this: Why do some structures end with an array of size 1?
Note: In Raymond Chen's article, there's a typo/bug in an example initializing the 'flexible' array. It should read:
如果您可以将应用程序限制为仅需要几个已知大小,那么您可以使用模板有效地实现灵活的数组。
If you can restrict your application to only require a few known sizes, then you can effectively achieve a flexible array with a template.
第二个不会包含元素,而是指向
blah
之后。因此,如果您有这样的结构:您可以执行以下操作:
在这种情况下,
c
将表现为具有 5 个int
的数组,但数组中的数据将在something
结构之后。我正在开发的产品使用它作为大小字符串:
由于受支持的架构,这将消耗 8 个字节加上
分配的
。当然,所有这些都是 C 语言,但是 g++ 可以顺利地接受它。
The second one will not contain elements but rather will point right after
blah
. So if you have a structure like this:you can do things like this:
In this case
c
will behave as an array with 5int
s but the data in the array will be after thesomething
structure.The product I'm working on uses this as a sized string:
Because of the supported architectures this will consume 8 bytes plus
allocated
.Of course all this is C but g++ for example accepts it without a hitch.
一项提案正在进行中,可能会成为未来的 C++ 版本。
请参阅http://www.open-std .org/jtc1/sc22/wg21/docs/papers/2018/p1039r0.html 了解详细信息(该提案相当新,因此可能会发生变化)
A proposal is underway, and might make into some future C++ version.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1039r0.html for details (the proposal is fairly new, so it's subject to changes)
如果您只需要
,那么您根本不需要该结构,您可以简单地处理 malloc'ed/new'ed int 数组。
如果您在开头有一些成员:
那么在 C++ 中,我想您可以将
foo
替换为foo
成员函数:使用示例:
此类型不存在严格的别名问题此处将内存转换为初始结构,因为内存是动态的(没有声明的类型)。
If you only want
then you don't need the struct at all an you can simply deal with a malloc'ed/new'ed int array.
If you have some members at the beginning:
then in C++, I suppose you could replace
foo
with afoo
member function:Example use:
There's no strict aliasing issues with this type of casting of the memory past the initial struct here because the memory is dynamic (has no declared type).
灵活数组尚未成为 C++ 标准的一部分。这就是
int foo[]
或int foo[0]
可能无法编译的原因。虽然有一个提案讨论过,但尚未被最新版本的 C++ (C++2b) 接受。然而,几乎所有现代编译器都通过编译器扩展来支持它。
问题是,如果您使用最高警告级别的扩展 (
-Wall --pedantic
),可能会导致警告。解决此问题的一种方法是使用包含一个元素的数组并进行越界访问。虽然此解决方案符合规范(dcl.array 和 < a href="https://timsong-cpp.github.io/cppwp/expr.add#4" rel="nofollow noreferrer">expr.add),大多数编译器都会生成有效的代码,甚至
clang -fsanitize=undefined
对此感到满意:演示< /a>
Having all that said, if you want your code to be standard compliant and do not depend on any compiler extension, you will have to avoid using this feature.
Flexible arrays are not part of the C++ standard yet. That is why
int foo[]
orint foo[0]
may not compile. While there is a proposal being discussed, it has not been accepted to the newest revision of C++ (C++2b) yet.However, almost all modern compiler do support it via compiler extensions.
The catch is that if you use this extension with the highest warning level (
-Wall --pedantic
), it may result into a warning.A workaround to this is to use an array with one element and do access out of bounds. While this solution is UB by the spec (dcl.array and expr.add), most of the compilers will produce valid code and even
clang -fsanitize=undefined
is happy with it:demo
Having all that said, if you want your code to be standard compliant and do not depend on any compiler extension, you will have to avoid using this feature.
我在声明可从 C++ 代码中使用的灵活数组成员时遇到了同样的问题。通过查看 glibc 头文件,我发现灵活数组成员有一些用法,例如在 struct inotify 中声明如下(省略注释和一些不相关的成员)
:
__flexarr
宏又被定义为我不熟悉
MSVC
编译器,但可能您必须根据MSVC< 添加一个条件宏/代码> 版本。
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. instruct inotify
which is declared as follows (comments and some unrelated members omitted):The
__flexarr
macro, in turn is defined asI'm not familar with
MSVC
compiler, but probably you'd have to add one more conditional macro depending onMSVC
version.然而,clang 文档说,标准 C++ 不支持灵活的数组成员。
“除了此处列出的语言扩展之外,Clang 还旨在支持广泛的 GCC 扩展。”
C++ 的 gcc 文档说。
“GNU 编译器为 C++ 语言提供了这些扩展(并且您还可以在 C++ 程序中使用大多数 C 语言扩展)。”
C 文档的 gcc 文档支持零长度数组。
https://gcc.gnu.org/onlinedocs/gcc/Zero-Length。 html
Flexible array members are not supported in standard C++, however the clang documentation says.
"In addition to the language extensions listed here, Clang aims to support a broad range of GCC extensions."
The gcc documentation for C++ says.
"The GNU compiler provides these extensions to the C++ language (and you can also use most of the C language extensions in your C++ programs)."
And the gcc documentation for C documents support for arrays of zero length.
https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
更好的解决方案是将其声明为指针:
或者更好的是,将其声明为 std::vector :
The better solution is to declare it as a pointer:
Or better yet, to declare it as a
std::vector
: