我想要一个可变大小的结构,但我想将具有特定大小的结构实例嵌入到另一个结构中。想法是这样的:
struct grid {
size_t width, height;
int items[ /* width * height */ ];
};
struct grid_1x1 {
size_t width, height;
int items[1];
};
struct grid_holder {
struct grid_1x1 a, b;
};
int main(void)
{
struct grid_holder h = {
.a = { .width = 1, .height = 1, .items = { 0 } },
.b = { .width = 1, .height = 1, .items = { 0 } },
};
struct grid *a = (struct grid *)&h.a, *b = (struct grid *)&h.b;
}
Run Code Online (Sandbox Code Playgroud)
如果我的所有代码都假设 的items成员struct grid具有width * height元素,那么可以像我上面那样进行强制a转换吗?b
换句话说,假设结构在其他方面相同,则具有一个元素的灵活数组成员是否始终与具有一个元素的固定大小数组成员具有相同的偏移量和大小?我想要一个基于 C99 标准的答案。如果偏移量可能不同,是否有其他方法可以实现我在开头所述的目标?
是的,C 标准没有定义该行为。
\n\nC 2018 6.5 7 或 C 1999 6.5 7 中关于哪些类型可用于访问对象的规则不仅仅是关于对象的布局和表示方式。因此,问题 \xe2\x80\x9c 中的句子换句话说,假设结构在其他方面相同,则具有一个元素的灵活数组成员是否始终与具有一个元素的固定大小数组成员具有相同的偏移量和大小?\ xe2\x80\x9d 不正确。具有相同的偏移量和大小,即使具有相同的结构定义,也不会使结构兼容别名。
\n\n不同的结构是故意不同的类型。考虑这两种类型:
\n\ntypedef struct { double real, imaginary; } Complex;\ntypedef struct { double x, y; } Coordinates;\nRun Code Online (Sandbox Code Playgroud)\n\n这些结构具有相同的定义(成员名称除外,但即使它们的名称相同,以下内容也成立),但根据 C 标准,它们是不同且不兼容的类型。这意味着在例程中,例如:
\n\ndouble foo(Complex *a, Coordinates *b)\n{\n a->real = 3; a->imaginary = 4;\n b->x = 5; b->y = 6;\n return sqrt(a->real*a->real + a->imaginary*a->imaginary);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n编译器被允许在不能改变的return 5;基础上优化最后一条语句,因为和不能指向同一个对象,或者,如果它们是,则行为b->x = 5; b->y = 6;aabb->x = 5; b->y = 6;则 的行为未定义。
因此,关于别名的 C 规则是关于兼容类型以及特定情况下的各种例外。它们主要不是关于结构如何布局的。
\n\n与上面具有不同但定义相同的结构的示例相比,当我们有多个指向同一结构类型的指针时,编译器不能假设a并且b不是同一对象的别名(不同的名称)。在:
double foo(Complex *a, Complex *b)\n{\n a->real = 3; a->imaginary = 4;\n b->real = 5; b->imaginary = 6;\n return sqrt(a->real*a->real + a->imaginary*a->imaginary);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n编译器不能假设返回值为 5,因为a和b可能指向同一个对象,在这种情况下b->real = 5; b->imaginary = 6;会更改a。