只是好奇,如果我int array[0];在代码中定义零长度数组会发生什么?海湾合作委员会根本没有抱怨.
示例程序
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
澄清
我实际上是在试图弄清楚零长度数组是否以这种方式初始化,而不是像Darhazer的注释中那样指向可变长度,是否优化了.
这是因为我必须释放一些代码,所以我想弄清楚我是否必须处理SIZE定义为的情况0,这在一些静态定义的代码中会发生int array[SIZE];
我真的很惊讶海湾合作委员会没有抱怨,这导致了我的问题.根据我收到的答案,我认为缺少警告主要是因为支持未使用新[]语法更新的旧代码.
因为我主要是想知道这个错误,所以我将Lundin的答案标记为正确(Nawaz是第一个,但它并不完整) - 其他人指出它实际用于尾部填充结构,虽然相关,但不是正是我想要的.
Mat*_* M. 79
通常情况下,不允许这样做.
然而,在C中使用灵活阵列是当前的做法.
C99 6.7.2.1,§16:作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这被称为灵活的阵列成员.
示范:
struct Array {
size_t size;
int content[];
};
Run Code Online (Sandbox Code Playgroud)
这个想法是你会分配它:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
您也可以静态使用它(gcc扩展名):
Array a = { 3, { 1, 2, 3 } };
Run Code Online (Sandbox Code Playgroud)
这也称为尾部填充结构(此术语早于C99标准的出版)或结构破解(感谢Joe Wreschnig指出它).
然而,这种语法最近才在C99中标准化(并保证了效果).在需要恒定尺寸之前.
1 是可移动的方式,虽然它很奇怪0 更好地表明了意图,但就标准而言并不合法,并且作为某些编译器(包括gcc)的扩展支持然而,尾部填充练习依赖于存储可用(小心malloc)的事实,因此通常不适合堆栈使用.
Lun*_*din 79
数组的大小不能为零.
ISO 9899:2011 6.7.6.2:
如果表达式是常量表达式,则其值应大于零.
上述文本对于普通数组都是正确的(第1段).对于VLA(可变长度数组),如果表达式的值小于或等于零,则行为未定义(第5段).这是C标准中的规范性文本.不允许编译器以不同方式实现它.
gcc -std=c99 -pedantic 对非VLA案件发出警告.
Naw*_*waz 57
在标准C和C++,大小为零的阵列不允许..
如果您正在使用GCC,请使用-pedantic选项进行编译.它会发出警告,说:
zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]
在C++的情况下,它给出了类似的警告.
Jam*_*nze 24
这完全是非法的,而且一直都是,但很多编译器忽略了发出错误的信号.我不确定你为什么要这样做.我所知道的一个用途是从布尔值触发编译时错误:
char someCondition[ condition ];
Run Code Online (Sandbox Code Playgroud)
如果condition是false,那么我得到一个编译时错误.但是,因为编译器允许这样做,我已经开始使用:
char someCondition[ 2 * condition - 1 ];
Run Code Online (Sandbox Code Playgroud)
这给出了1或-1的大小,我从来没有找到一个接受大小为-1的编译器.
我将补充说,在这个论点上有一整页关于gcc的在线文档.
一些引言:
GNU C中允许零长度数组.
在ISO C90中,您必须为内容提供长度为1的内容
和
3.0之前的GCC版本允许静态初始化零长度数组,就好像它们是灵活的数组一样.除了那些有用的案例之外,它还允许在破坏以后数据的情况下进行初始化
所以你可以
int arr[0] = { 1 };
Run Code Online (Sandbox Code Playgroud)
和繁荣:-)
零长度数组的另一个用途是用于制作可变长度的对象(前C99).零长度数组是不同从柔性阵列具有[]无0.
引自gcc doc:
在GNU C中允许零长度数组.它们作为结构的最后一个元素非常有用,它实际上是一个可变长度对象的头:
Run Code Online (Sandbox Code Playgroud)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运算符.
一个真实世界的例子是零长度数组struct kdbus_item中kdbus.h(Linux内核模块).
如果允许结构中的零大小数组声明将是有用的,并且如果语义是这样的:(1)它们将强制对齐但是否则不分配任何空间,并且(2)索引数组将被认为是在结果指针与结构存在于同一内存块中的情况.任何C标准都不允许这样的行为,但是一些较旧的编译器在它成为编译器的标准之前允许它允许带有空括号的不完整数组声明.
结构hack,通常使用大小为1的数组实现,是狡猾的,我不认为有任何要求编译器不要破坏它.例如,我希望,如果编译器看到的int a[1],这将是关于其权利范围内a[i]的a[0].如果有人试图通过类似的东西解决结构黑客的对齐问题
typedef struct {
uint32_t size;
uint8_t data[4]; // Use four, to avoid having padding throw off the size of the struct
}
编译器可能会变得聪明,并假设数组大小确实是四:
; As written foo = myStruct->data[i]; ; As interpreted (assuming little-endian hardware) foo = ((*(uint32_t*)myStruct->data) >> (i << 3)) & 0xFF;
这样的优化可能是合理的,特别是如果myStruct->data可以在相同的操作中加载到寄存器中myStruct->size.我在禁止这种优化的标准中一无所知,但当然它会破坏任何可能期望访问超出第四个元素的代码的代码.