[英]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.