c - 从具有灵活数组成员的结构转换为没有其他相同成员的结构是否是未定义的行为?
问题描述
我想要一个可变大小的结构,但我想将具有一定大小的结构实例嵌入到另一个结构中。这是想法:
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;
}
如果我所有的代码都假设 的items
成员struct grid
具有width * height
元素,那么可以a
像b
上面那样进行强制转换吗?
换句话说,考虑到结构在其他方面相同,具有一个元素的灵活数组成员是否始终具有与具有一个元素的固定大小数组成员相同的偏移量和大小?我想要一个基于 C99 标准的答案。如果偏移量可能不同,是否有另一种方法可以实现我在开始时提出的目标?
解决方案
是的,行为不是由 C 标准定义的。
C 2018 6.5 7 或 C 1999 6.5 7 中关于哪些类型可用于访问对象的规则不仅仅是关于对象的布局和表示方式。所以问题中的句子“换句话说,一个元素的灵活数组成员是否总是与一个元素的固定大小的数组成员具有相同的偏移量和大小,假设结构在其他方面是相同的?” 是不正确的。具有相同的偏移量和大小,即使具有相同的结构定义,也不会使结构与别名兼容。
不同的结构是故意不同的类型。考虑这两种类型:
typedef struct { double real, imaginary; } Complex;
typedef struct { double x, y; } Coordinates;
这些结构具有相同的定义(除了成员名称,但即使它们的名称相同,以下内容也成立),但根据 C 标准,它们是不同且不兼容的类型。这意味着在例程中,例如:
double foo(Complex *a, Coordinates *b)
{
a->real = 3; a->imaginary = 4;
b->x = 5; b->y = 6;
return sqrt(a->real*a->real + a->imaginary*a->imaginary);
}
允许编译器优化最后一条语句,因为return 5;
它b->x = 5; b->y = 6;
不能改变a
,因为a
并且b
不能指向同一个对象,或者,如果它们是,b->x = 5; b->y = 6;
则未定义的行为。
因此,关于别名的 C 规则是关于兼容类型以及特定情况下的各种例外。它们主要不是关于结构的布局方式。
与上面具有不同但定义相同的结构的示例相比,当我们有多个指向相同结构类型的指针时,编译器不能假定a
并且b
不是同一对象的别名(不同名称)。在:
double foo(Complex *a, Complex *b)
{
a->real = 3; a->imaginary = 4;
b->real = 5; b->imaginary = 6;
return sqrt(a->real*a->real + a->imaginary*a->imaginary);
}
编译器不能假定返回值为 5,因为a
并且b
可能指向同一个对象,在这种情况下b->real = 5; b->imaginary = 6;
会更改a
.
推荐阅读
- python - 如何在不克隆 repo 的情况下使用 python 更新 github repo 中的现有文件?
- python - 如何让python从列表中随机选择一些东西,如果在输入提示中输入,它将按预期显示确切的答案
- c++ - 为套接字编程动态分配内存
- javascript - 我如何使用 gatsby 和 Netlify CMS 进行数据收集
- ruby-on-rails - ARM64架构(M1芯片):无法安装pg gem(使用PostgresApp)
- python - 根据另一个数组的样本从 numpy 数组中获取样本
- postgresql - PostgreSQL - 触发 INSERT 或 UPDATE
- python - 如何找到按月分组的熊猫数据框中的最高中值?
- javascript - 对数组和 SUM 项目计数进行排序
- splunk - Splunk:列出可以访问的索引和来源