结构中的Unsized数组声明
为什么C允许这样:
typedef struct { int arr []; } s;
数组arr
没有指定大小?
这是C99function称为灵活数组 ,其主要特点是允许使用变量长度数组,如结构和R中的特征..在这个答案中,灵活数组成员的另一个问题提供了使用灵活数组而不是指针的好处列表。 第6.7.2.1
节结构和工会 6.7.2.1
第16段中的C99标准草案说:
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活的arrays成员。 在大多数情况下,忽略灵活的数组成员。 特别地,结构的尺寸好像省略了柔性arrays构件,除了它可以具有比遗漏所暗示的更多的拖尾填充。 […]
因此,如果你有一个s*
,除了结构所需的空间之外你还要为数组分配空间,通常你会在结构中有其他成员:
s *s1 = malloc( sizeof(struct s) + n*sizeof(int) ) ;
标准草案实际上在第17段中有一个有启发性的例子:
示例声明后:
struct s { int n; double d[]; };
结构struct具有灵活的数组成员
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中的灵活arrays。 灵活的数组成员是struct / union末尾的未知大小的成员。
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活的arrays成员。 在大多数情况下,忽略灵活的数组成员。 特别地,结构的尺寸好像省略了柔性arrays构件,除了它可以具有比遗漏所暗示的更多的拖尾填充。
您也可以首先查看结构黑客攻击的原因 。
目前尚不清楚它是合法的还是便携的,但它很受欢迎。 该技术的实现可能如下所示:
#include #include 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字段可以保存所请求的名称(不只是一个字符,如结构声明所示)。
尽管它很受欢迎,但这种技术也有点臭名昭着 – 丹尼斯·里奇称其为“C实施中无根据的笨拙”。 官方解释认为它并不严格符合C标准,尽管它似乎在所有已知的实施中都有效。 仔细检查数组边界的编译器可能会发出警告。