为什么 C 允许这样做:
typedef struct s { int arr[]; } s;
数组arr
没有指定大小?
答案 0 :(得分:12)
这是C99功能称为灵活数组,主要功能是允许use variable length array like features inside a struct和 R .. 在此answer to another question on flexible array members中提供一个通过指针使用灵活数组的好处列表。 6.7.2.1
结构和联合说明符段 16 中的draft C99 standard表示:
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可以 有一个不完整的数组类型;这被称为灵活的阵列成员。在大多数情况下, 灵活的数组成员被忽略。特别是,结构的大小就像是 省略了灵活的数组成员,除了它可能有更多的尾随填充 遗漏意味着。 [...]
因此,除了 struct 所需的空间之外,如果你有一个s*
,你将为数组分配空间,通常你会在结构中有其他成员:
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
的偏移可能不一样。)
答案 1 :(得分:4)
您可能正在寻找C99中的灵活阵列。 灵活数组成员是struct / union末尾未知大小的成员。
作为一种特殊情况,结构的最后一个元素有多个 命名成员可能具有不完整的数组类型;这叫做a 灵活的阵列成员。在大多数情况下,灵活的阵列成员 被忽略了。特别是,结构的大小就像是 柔性阵列成员被省略,除了它可能有更多 尾随填充比遗漏意味着暗示。
您也可以首先查看reason for the 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标准,虽然它似乎确实有效 在所有已知的实现中。检查数组边界的编译器 小心翼翼地发出警告。