为什么C允许这样做:
typedef 结构体 { int arr[]; } s;
数组arr
没有指定大小?
这是称为灵活数组的 C99 功能,主要功能是允许在结构和R中使用可变长度数组等功能。在这个对灵活数组成员的另一个问题的回答中,提供了使用灵活数组而不是指针的好处列表。结构和联合说明符第16段中的C99 标准草案说:6.7.2.1
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。[...]
因此,如果您有 a ,则除了structs*
所需的空间之外,您还将为数组分配空间,通常您在结构中还有其他成员:
s *s1 = malloc( sizeof(struct s) + n*sizeof(int) ) ;
标准草案实际上在第17段中有一个指导性的例子:
示例声明后:
struct s { int n; double d[]; };
结构 struct
s
具有灵活的数组成员d
。一个典型的使用方法是:int m = /* some value */; struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
并假设调用
malloc
成功,在大多数情况下,指向的对象的p
行为就像p
被声明为:struct { int n; double d[m]; } *p;
(在某些情况下,这种等价性会被破坏;特别是,成员的偏移量
d
可能不一样)。
您可能正在 C99 中寻找灵活的数组。灵活数组成员是结构/联合末尾的未知大小的成员。
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。
您还可以首先查看struct hack的原因。
目前尚不清楚它是合法的还是可移植的,但它相当受欢迎。该技术的实现可能如下所示:
#include <stdlib.h>
#include <string.h>
struct name *makename(char *newname)
{
struct name *ret =
malloc(sizeof(struct name)-1 + strlen(newname)+1);
/* -1 for initial [1]; +1 for \0 */
if(ret != NULL) {
ret->namelen = strlen(newname);
strcpy(ret->namestr, newname);
}
return ret;
}
这个函数分配一个调整大小的名称结构的实例,以便 namestr 字段可以保存请求的名称(不仅仅是一个字符,正如结构声明所暗示的那样)。
尽管它很受欢迎,但该技术也有点臭名昭著—— 丹尼斯·里奇( Dennis Ritchie)称其为“与 C 实现毫无根据的亲密关系”。官方解释认为它并不严格符合 C 标准,尽管它似乎在所有已知的实现下都有效。仔细检查数组边界的编译器可能会发出警告。