考虑以下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类型(例如,通过添加构造函数?
答案 0 :(得分:2)
Rect2::pos
和Rect2::size
之间填充。所以为了确保,我会将编译器特定的属性添加到" pack"字段,从而保证所有int
s相邻且紧凑。这不是关于C与C ++的关系,更多的是关于你可能使用两个"不同的"编译时使用两种语言进行编译,即使这些编译器来自单一供应商。reinterpret_cast
将指向一种类型的指针转换为指向另一种类型的指针,您可能会违反"严格别名"规则。假设您之后取消引用指针,在这种情况下就是这样。private
之类的访问说明符可能会改变布局(实际上,不仅在理论上) 答案 1 :(得分:0)
Rect1和Rect2对象的内存布局是否始终相同?
是。只要某些明显的要求成立,它们就保证是相同的。这些明显的要求是关于目标平台/架构在对齐和字大小方面是相同的。换句话说,如果你愚蠢地为不同的目标平台编译C和C ++代码(例如,32位对64位)并尝试混合它们,那么你就会遇到麻烦,否则你就不会有#39 ;不用担心,C ++编译器基本上需要产生与在C中相同的内存布局,并且对于给定的字大小和对齐,ABI在C中是固定的。
具体来说,我可以安全地从Rect2 * reterpret_cast到Rect1 *并假设Rect2对象中的所有四个int值一对一匹配到Rect1中的四个int中吗?
是。从第一个答案开始。
如果我将Rect2更改为非POD类型,例如,它会有所不同吗?通过添加构造函数?
不,或者至少,不再是。唯一重要的是该类仍然是standard-layout类,它不受构造函数或任何其他非虚拟成员的影响。这是自C ++ 11(2011)标准以来有效的。在此之前,该语言是关于" POD-types",正如我刚刚为标准布局提供的链接中所解释的那样。如果你有一个pre-C ++ 11编译器,那么它很可能仍然使用与C ++ 11标准相同的规则(C ++ 11标准规则(对于标准布局和普通类型)基本上是编写以匹配所有编译器供应商已经做过的事情。
答案 2 :(得分:0)
对于像您这样的标准布局类,您可以轻松地检查结构的成员如何从结构开始定位。
#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
....
答案 3 :(得分:-3)
是的,它们永远都是一样的。 您可以尝试在此处运行以下示例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;
}