[英]C/C++ Struct memory layout equivalency
考虑以下C结构和C ++结构声明:
extern "C" { // if this matters
typedef struct Rect1 {
int x, y;
int w, h;
} Rect1;
}
struct Vector {
int x;
int y;
}
struct Rect2 {
Vector pos;
Vector size;
}
Rect1
和Rect2
对象的内存布局是否始终相同?
具体来说,我可以放心reinterpret_cast
从Rect2*
到Rect1*
,并假设所有四个int
中的值Rect2
对象匹配一对一的四个int
以秒Rect1
?
如果我将Rect2
更改为非POD类型(例如通过添加构造函数),会有所不同吗?
Rect2::pos
和Rect2::size
之间可能(合法地)填充。 因此,为确保确定,我将添加特定于编译器的属性以“打包”字段,从而确保所有int
都是相邻且紧凑的。 这与C与C ++的关系不那么多,而更多的事实是,当使用两种语言进行编译时,即使这些编译器来自同一家供应商,也可能会使用两个“不同的”编译器。 reinterpret_cast
将一种类型的指针转换为另一种类型的指针,您可能会违反“严格别名”规则。 假设您之后确实取消了指针的引用,在这种情况下,您将取消引用。 private
访问说明符可能会更改布局(实际上,不仅在理论上)。 Rect1和Rect2对象的内存布局是否始终相同?
是。 只要满足某些明显的要求,就可以保证它们是相同的。 这些明显的要求是关于目标平台/体系结构在对齐方式和字长方面都相同。 换句话说,如果您愚蠢到为不同的目标平台(例如32位和64位)编译C和C ++代码并尝试将它们混合使用,那么您将遇到麻烦,否则,您不必令人担心的是,基本上要求C ++编译器产生与在C中相同的内存布局,并且对于给定的字长和对齐方式,ABI在C中固定。
具体来说,我是否可以安全地将Rect2 *从Rect2 *重新解释为Rect1 *,并假设Rect2对象中的所有四个int值都与Rect1中的四个int一对一匹配?
是。 从第一个答案开始。
如果我将Rect2更改为非POD类型(例如通过添加构造函数),会有所不同吗?
不,或者至少不再。 唯一重要的是,该类仍然是标准布局类,不受构造函数或任何其他非虚拟成员的影响。 从C ++ 11(2011)标准开始有效。 在此之前,该语言是关于“ POD类型”的,正如我刚才在标准布局中给出的链接中所述。 如果您使用的是C ++ 11之前的编译器,那么很有可能仍按与C ++ 11标准相同的规则进行工作(C ++ 11标准规则(对于标准布局和平凡类型)基本上是编写以匹配所有编译器供应商已经做的事情。
对于像您这样的标准布局类,您可以轻松地从结构开始检查结构成员的位置。
#include <cstddef>
int x_offset = offsetof(struct Rect1,x); // probably 0
int y_offset = offsetof(struct Rect1,y); // probably 4
....
pos_offset = offsetof(struct Rect2,pos); // probably 0
....
是的,它们将始终相同。 您可以尝试在此处运行以下示例cpp.sh它按预期运行。
// Example program
#include <iostream>
#include <string>
typedef struct Rect1 {
int x, y;
int w, h;
} Rect1;
struct Vector {
int x;
int y;
};
struct Rect2 {
Vector pos;
Vector size;
};
struct Rect3 {
Rect3():
pos(),
size()
{}
Vector pos;
Vector size;
};
int main()
{
Rect1 r1;
r1.x = 1;
r1.y = 2;
r1.w = 3;
r1.h = 4;
Rect2* r2 = reinterpret_cast<Rect2*>(&r1);
std::cout << r2->pos.x << std::endl;
std::cout << r2->pos.y << std::endl;
std::cout << r2->size.x << std::endl;
std::cout << r2->size.y << std::endl;
Rect3* r3 = reinterpret_cast<Rect3*>(&r1);
std::cout << r3->pos.x << std::endl;
std::cout << r3->pos.y << std::endl;
std::cout << r3->size.x << std::endl;
std::cout << r3->size.y << std::endl;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.