用于初始化结构的 void 指针强制转换
Void pointer castings to initialize structs
我正在研究面向对象的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++也是有效的。
相关文章:
- 转换指针引用的字符串
- 无法向上转换指针到指针参数
- 混合转换指针和引用
- 堆栈对象的强制转换指针
- 基类到派生模板类的强制转换指针,而不知道类型
- 删除类型转换指针的最佳方法
- 管理到本机值类转换:强制转换指针是否安全?
- 转换指针类型
- 为什么函数不能正确强制转换指针(从基类到派生类)
- 当我们递增下面的类型转换指针时会发生什么?
- 类型强制转换指针构造函数调用
- 如何转换(指针向量)-->(指向指针数组的指针)
- 如何从类功能转换指针
- 在C++对象中:我应该使用父类强制转换指针,还是应该使用实际类本身进行强制转换
- Delphi中的类型转换指针添加
- C++分段错误(核心转储)错误 - 强制转换指针/将函数值返回到线程
- 以C++和运算符优先级键入指向数组成员的强制转换指针
- C++动态强制转换指针的内存清理
- 转换指针和引用的好处
- 在c++中转换指针