如果我在 C/C++ 中定义一个 0 大小的数组会发生什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9722632/
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
What happens if I define a 0-size array in C/C++?
提问by Alex Koay
Just curious, what actually happens if I define a zero-length array int array[0];
in code? GCC doesn't complain at all.
只是好奇,如果我int array[0];
在代码中定义一个长度为零的数组,实际上会发生什么?GCC 根本没有抱怨。
Sample Program
示例程序
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
Clarification
澄清
I'm actually trying to figure out if zero-length arrays initialised this way, instead of being pointed at like the variable length in Darhazer's comments, are optimised out or not.
我实际上是想弄清楚零长度数组是否以这种方式初始化,而不是像 Darhazer 评论中的可变长度那样指向,是否被优化。
This is because I have to release some code out into the wild, so I'm trying to figure out if I have to handle cases where the SIZE
is defined as 0
, which happens in some code with a statically defined int array[SIZE];
这是因为我必须将一些代码发布到野外,所以我试图弄清楚是否必须处理SIZE
定义为 的情况0
,这种情况发生在一些具有静态定义的代码中int array[SIZE];
I was actually surprised that GCC does not complain, which led to my question. From the answers I've received, I believe the lack of a warning is largely due to supporting old code which has not been updated with the new [] syntax.
我实际上很惊讶 GCC 没有抱怨,这导致了我的问题。从我收到的答案来看,我认为没有警告主要是由于支持尚未使用新 [] 语法更新的旧代码。
Because I was mainly wondering about the error, I am tagging Lundin's answer as correct (Nawaz's was first, but it wasn't as complete) -- the others were pointing out its actual use for tail-padded structures, while relevant, isn't exactly what I was looking for.
因为我主要想知道错误,所以我将 Lundin 的答案标记为正确(Nawaz 是第一个,但它并不完整)——其他人指出它实际用于尾垫结构,虽然相关,但不是这正是我要找的。
采纳答案by Lundin
An array cannot have zero size.
数组的大小不能为零。
ISO 9899:2011 6.7.6.2:
ISO 9899:2011 6.7.6.2:
If the expression is a constant expression, it shall have a value greater than zero.
如果表达式是一个常量表达式,它的值应该大于零。
The above text is true both for a plain array (paragraph 1). For a VLA (variable length array), the behavior is undefined if the expression's value is less than or equal to zero (paragraph 5). This is normative text in the C standard. A compiler is not allowed to implement it differently.
上面的文字对于普通数组(第 1 段)都是正确的。对于 VLA(可变长度数组),如果表达式的值小于或等于 0(第 5 段),则行为未定义。这是 C 标准中的规范性文本。不允许编译器以不同方式实现它。
gcc -std=c99 -pedantic
gives a warning for the non-VLA case.
gcc -std=c99 -pedantic
对非 VLA 情况给出警告。
回答by Matthieu M.
Normally, it is not allowed.
通常,这是不允许的。
However it's been current practice in C to use flexible array member (FAM).
然而,目前在 C 中的做法是使用灵活的数组成员 ( FAM)。
C99 6.7.2.1, §16: As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
C99 6.7.2.1, §16:作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。
Demonstration:
示范:
struct Array {
size_t size;
int content[];
};
The idea is that you would then allocate it so:
这个想法是你会这样分配它:
void foo(size_t x) {
Array* array = malloc(sizeof(size_t) + x * sizeof(int));
array->size = x;
for (size_t i = 0; i != x; ++i) {
array->content[i] = 0;
}
}
You might also use it statically (gcc extension):
您也可以静态使用它(gcc 扩展名):
Array a = { 3, { 1, 2, 3 } };
This is also known as tail-padded structures(this term predates the publication of the C99 Standard) or struct hack(thanks to Joe Wreschnig for pointing it out).
这也称为尾部填充结构(该术语早于 C99 标准的发布)或struct hack(感谢 Joe Wreschnig 指出)。
However this syntax was standardized (and the effects guaranteed) only lately in C99. Before a constant size was necessary.
然而,这种语法直到最近才在 C99 中标准化(并且保证了效果)。在需要恒定大小之前。
1
was the portable way to go, though it was rather strange0
was better at indicating intent, but not legal as far as the Standard was concerned and supported as an extension by some compilers (including gcc)
1
是便携式的方式,虽然它很奇怪0
更好地表明意图,但就标准而言并不合法,并且被某些编译器(包括 gcc)支持作为扩展
The tail padding practice, however, relies on the fact that storage is available (careful malloc
) so is not suitedto stack usage in general.
然而,尾部填充实践依赖于存储可用(小心malloc
)这一事实,因此通常不适合堆栈使用。
回答by Nawaz
In Standard C and C++, zero-size array is notallowed..
在标准C和C ++,大小为零的阵列不允许..
If you're using GCC, compile it with -pedantic
option. It will give warning, saying:
如果您使用 GCC,请使用-pedantic
选项编译它。它会发出警告,说:
zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]
zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]
In case of C++, it gives similar warning.
在 C++ 的情况下,它会给出类似的警告。
回答by James Kanze
It's totally illegal, and always has been, but a lot of compilers neglect to signal the error. I'm not sure why you want to do this. The one use I know of is to trigger a compile time error from a boolean:
这是完全非法的,而且一直都是,但是很多编译器都忽略了发出错误信号。我不确定你为什么要这样做。我知道的一个用途是从布尔值触发编译时错误:
char someCondition[ condition ];
If condition
is a false, then I get a compile time error. Because
compilers do allow this, however, I've taken to using:
如果condition
是假的,那么我得到一个编译时错误。但是,因为编译器确实允许这样做,所以我已经开始使用:
char someCondition[ 2 * condition - 1 ];
This gives a size of either 1 or -1, and I've never found a compiler which would accept a size of -1.
这给出了 1 或 -1 的大小,而且我从未找到接受 -1 大小的编译器。
回答by xanatos
I'll add that there is a whole pageof the online documentation of gcc on this argument.
我要补充一点,关于这个论点,gcc 的在线文档有一整页。
Some quotes:
一些引用:
Zero-length arrays are allowed in GNU C.
GNU C 中允许零长度数组。
In ISO C90, you would have to give contents a length of 1
在 ISO C90 中,您必须为内容指定长度为 1
and
和
GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays. In addition to those cases that were useful, it also allowed initializations in situations that would corrupt later data
3.0 之前的 GCC 版本允许静态初始化零长度数组,就好像它们是灵活的数组一样。除了那些有用的情况外,它还允许在会破坏以后数据的情况下进行初始化
so you could
所以你可以
int arr[0] = { 1 };
and boom :-)
和繁荣:-)
回答by Duke
Another use of zero-length arrays is for making variable-length object (pre-C99). Zero-length arraysare differentfrom flexible arrayswhich have [] without 0.
零长度数组的另一个用途是制作可变长度对象(C99 之前)。零长度数组是不同从柔性阵列[]无0具有。
Quoted from gcc doc:
引用自gcc 文档:
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object:
struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length;
In ISO C99, you would use a flexible array member, which is slightly different in syntax and semantics:
- Flexible array members are written as contents[] without the 0.
- Flexible array members have incomplete type, and so the sizeof operator may not be applied.
零长度数组在 GNU C 中是允许的。它们作为结构的最后一个元素非常有用,它实际上是可变长度对象的标头:
struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length;
在 ISO C99 中,您将使用灵活的数组成员,它在语法和语义上略有不同:
- 灵活的数组成员写为没有 0 的内容 []。
- 灵活的数组成员具有不完整的类型,因此可能不应用 sizeof 运算符。
A real-world example is zero-length arrays of struct kdbus_item
in kdbus.h(a Linux kernel module).
一个真实世界的例子是零长度数组struct kdbus_item
中kdbus.h(Linux内核模块)。
回答by supercat
Zero-size array declarations within structs would be useful if they were allowed, and if the semantics were such that (1) they would force alignment but otherwise not allocate any space, and (2) indexing the array would be considered defined behavior in the case where the resulting pointer would be within the same block of memory as the struct. Such behavior was never permitted by any C standard, but some older compilers allowed it before it became standard for compilers to allow incomplete array declarations with empty brackets.
如果允许,结构中的零大小数组声明将很有用,并且如果语义是这样的:(1)它们将强制对齐但不分配任何空间,以及(2)索引数组将被视为在结果指针将与结构位于同一内存块中的情况。任何 C 标准都不允许这种行为,但一些较旧的编译器在它成为编译器的标准之前允许它允许带有空括号的不完整数组声明。
The struct hack, as commonly implemented using an array of size 1, is dodgy and I don't think there's any requirement that compilers refrain from breaking it. For example, I would expect that if a compiler sees int a[1]
, it would be within its rights to regard a[i]
as a[0]
. If someone tries to work around the alignment issues of the struct hack via something like
通常使用大小为 1 的数组实现的 struct hack 是狡猾的,我认为没有任何要求编译器避免破坏它。例如,我希望如果编译器看到int a[1]
,则将其a[i]
视为a[0]
. 如果有人试图通过类似的方法解决 struct hack 的对齐问题
typedef struct { uint32_t size; uint8_t data[4]; // Use four, to avoid having padding throw off the size of the struct }
a compiler might get clever and assume the array size really is four:
编译器可能会变得聪明并假设数组大小确实是四:
; As written foo = myStruct->data[i]; ; As interpreted (assuming little-endian hardware) foo = ((*(uint32_t*)myStruct->data) >> (i << 3)) & 0xFF;
Such an optimization might be reasonable, especially if myStruct->data
could be loaded into a register in the same operation as myStruct->size
. I know nothing in the standard that would forbid such optimization, though of course it would break any code which might expect to access stuff beyond the fourth element.
这种优化可能是合理的,特别是如果myStruct->data
可以在与myStruct->size
. 我不知道标准中的任何内容会禁止这种优化,尽管它当然会破坏任何可能期望访问第四个元素之外的内容的代码。