嵌套结构中的灵活数组成员
flexible array member in a nested struct
在嵌套结构中使用灵活的数组成员是否有效?那么我下面的示例代码是否可以保证在正常的编译器下按预期工作?
#include <stdio.h>
#include <stdlib.h>
struct d {
char c;
int ns[];
};
struct c {
struct d d;
};
struct b {
struct c c;
};
struct a {
int n;
struct b b;
};
int main() {
const int n = 10;
struct a *pa = malloc(sizeof(*pa) + n * sizeof(pa->b.c.d.ns[0]));
pa->n = n;
pa->b.c.d.c = 1;
for (int i = 0; i < n; ++i) {
pa->b.c.d.ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf("%d\n", pa->b.c.d.ns[i] + pa->b.c.d.c);
}
free(pa);
}
根据标准,它无效。我不确定它在实践中有多可靠。
C11 (ISO/IEC 9899:2011), §6.7.2.1.3 说了以下内容(强调我的):
A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
稍后,§6.7.2.1.18 阐明上述内容指的是灵活数组成员 (FAM):
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.
通过一些快速实验,GCC 和 Clang 都添加了正确对齐 FAM 所需的尾部填充,即使 struct
是嵌套的,并且仅在以下情况下警告具有 FAM 的结构是其他结构或数组的成员-Wpedantic
已通过,因此请将其视为一个标志,如果您愿意的话,它可能会起作用:)。不过感觉有点黑。
请注意,将 FAM 放在最后的任何地方可能没有意义。如果你这样做
struct e {
struct d d;
int n;
} e;
,那么e.d.ns[0]
和e.n
很可能在内存中重叠了
尝试这样的事情;
struct d {
char c;
int ns[];
};
struct a {
int n;
int d_fam[];
};
int main() {
const int n = 10;
struct a *pa = malloc(offsetof (struct a, d_fam) + offsetof (stuct d, ns) + n * sizeof(int));
struct d *pd = pa + (uintptr_t) offsetof (struct a, d_fam);
pa->n = n;
pd->c = 1;
for (int i = 0; i < n; ++i) {
pd->ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf ("%d\n", pd->ns[i] + pd->c);
}
free(pa);
}
在嵌套结构中使用灵活的数组成员是否有效?那么我下面的示例代码是否可以保证在正常的编译器下按预期工作?
#include <stdio.h>
#include <stdlib.h>
struct d {
char c;
int ns[];
};
struct c {
struct d d;
};
struct b {
struct c c;
};
struct a {
int n;
struct b b;
};
int main() {
const int n = 10;
struct a *pa = malloc(sizeof(*pa) + n * sizeof(pa->b.c.d.ns[0]));
pa->n = n;
pa->b.c.d.c = 1;
for (int i = 0; i < n; ++i) {
pa->b.c.d.ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf("%d\n", pa->b.c.d.ns[i] + pa->b.c.d.c);
}
free(pa);
}
根据标准,它无效。我不确定它在实践中有多可靠。
C11 (ISO/IEC 9899:2011), §6.7.2.1.3 说了以下内容(强调我的):
A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
稍后,§6.7.2.1.18 阐明上述内容指的是灵活数组成员 (FAM):
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.
通过一些快速实验,GCC 和 Clang 都添加了正确对齐 FAM 所需的尾部填充,即使 struct
是嵌套的,并且仅在以下情况下警告具有 FAM 的结构是其他结构或数组的成员-Wpedantic
已通过,因此请将其视为一个标志,如果您愿意的话,它可能会起作用:)。不过感觉有点黑。
请注意,将 FAM 放在最后的任何地方可能没有意义。如果你这样做
struct e {
struct d d;
int n;
} e;
,那么e.d.ns[0]
和e.n
很可能在内存中重叠了
尝试这样的事情;
struct d {
char c;
int ns[];
};
struct a {
int n;
int d_fam[];
};
int main() {
const int n = 10;
struct a *pa = malloc(offsetof (struct a, d_fam) + offsetof (stuct d, ns) + n * sizeof(int));
struct d *pd = pa + (uintptr_t) offsetof (struct a, d_fam);
pa->n = n;
pd->c = 1;
for (int i = 0; i < n; ++i) {
pd->ns[i] = i;
}
for (int i = 0; i < n; ++i) {
printf ("%d\n", pd->ns[i] + pd->c);
}
free(pa);
}