用于初始化结构的 void 指针强制转换

Void pointer castings to initialize structs

本文关键字:转换 指针 void 初始化 结构 用于      更新时间:2023-10-16

我正在研究面向对象的C编程(如何实现虚拟表),我看到了一些进行初始化的强制转换,我想知道是否:

1 - 是否有任何未定义的行为?

2 - 此代码是可移植的吗?

3 - 它在C++中是否也有效(定义明确且可移植)?

在我正在研究的实际代码中,没有像这里这样的简单数据成员,而是指向构造函数、析构函数和克隆函数的函数指针,但我只对这些类型的强制转换进行了很好的定义才感兴趣。

此代码使用 gcc 和 g++ 按预期编译和运行。

struct Point
{
int x;
int y;
};
struct Square
{
struct Point *topLeft;
struct Point *bottomRight;
int area;
};
int main()
{
void *square = calloc(1,sizeof(struct Square));
* (struct Point **) square = (struct Point *) calloc(1,sizeof(struct Point));
* ( ( (struct Point **) square) + 1) = (struct Point *) calloc(1,sizeof(struct Point));
struct Square *sqrptr = (struct Square *) square;
sqrptr->topLeft->x = 2;
sqrptr->topLeft->y = 3;
sqrptr->bottomRight->x = 5;
sqrptr->bottomRight->y = 7;
sqrptr->area = 20;
printf("Values: %d %d %d %dn", (** (struct Point **) square).x,
(** (struct Point **) square).y,
(** ( ( (struct Point **) square) + 1) ).x,
(** ( ( (struct Point **) square) + 1) ).y );
free(sqrptr->topLeft);
free(sqrptr->bottomRight);
free(sqrptr);
}

此外,根据瓦尔格林德的说法,没有内存泄漏。

编辑:我刚刚尝试使用C++样式的转换,g ++不会给出任何错误或警告消息。

我发布的这段代码具有未定义的行为,因为可以访问结构中的第二个数据成员:

* ( ( (struct Point **) square) + 1) = (struct Point *) calloc(1,sizeof(struct Point));

编译器可以对齐 Square 结构,以便第二个数据成员不会在第一个结构点之后立即启动。

但是,访问第一个数据成员在 C 和 C++ 中都是有效的,并且定义良好,因为在第一个数据成员之前没有填充:

结构对齐 C/C++

(C11, 6.7.2.1p15)"结构中可能存在未命名的填充 反对,但不是在开始时。

(C++11, 9.2p20) "因此,在 标准布局结构对象,但不是在其开头,根据需要 以实现适当的对齐">

因此,在结构的开头,我可以放置一个指向 VirtualTable 结构的指针,其中包含指向初始值设定项的函数指针并清理函数,并在普通 C 中实现面向对象的行为。这在C++也是有效的。