2011-07-26 41 views
1

以下結構X具有3個字節的有效負載和1個字節的填充構成:利用否則會浪費掉的填充空間

struct X 
{ 
    short a; 
    char b; 
}; 

memory layout: aab. 

以下結構Y有4個字節的有效載荷的和填充的2字節:

struct Y 
{ 
    X x; 
    char c; 
}; 

memory layout: aab.c. 

有什麼辦法可以保持X嵌套在Y裏面並且有sizeof(X) == 4 && sizeof(Y) == 4

memory layout: aabc 

理想情況下,我想這樣的空間優化,爲各類X(認爲X作爲模板參數)。

+2

爲什麼要禁用填充?如果你打算將它用於序列化,我不推薦這種方法。 –

+0

我不想禁用填充。我希望'X'被填充,而Y使用'X'的填充空間作爲額外的字符。 – fredoverflow

+0

所以你試圖從概念上將''內聯'到'Y'? – Mat

回答

0

對於希望顯而易見的原因既XY的大小不能四(如果有可能,X將有多個定義,其中填充用於通過Ychar正常填充一個和一個)。所以Y唯一的方法是4,如果X被改變以消除它的填充。這可以通過編譯器特定的編譯指示或指令來完成。但是,由於這可能導致X被未對齊訪問,因此它將有效地限制程序的可移植性(如果進行錯位訪問,某些體系結構甚至會崩潰)。

相反,你能更清楚地解釋你希望在這裏實現的最終結果嗎?

+0

如果您要使用特定於編譯器的編譯指示或指令來禁用「X」的填充,那麼編譯器在訪問「X」的成員時是否會執行正確的取消打包? ...這通常是爲什麼打包結構有性能問題,對吧? – Jason

+0

@Jason希望您的編譯器能夠理解目標系統不能自行完成錯誤對齊的訪問並生成代碼。標準中並沒有涉及'pack'這樣的指令,所以你真的不能爲特定的編譯器做出任何保證。 –

1

這是一個編譯器設置。內存訪問在某些情況下正常工作需要填充。在某些體系結構中,這是一個效率問題,而在另一些體系結構中,如果未正確對齊,程序將崩潰。在這種情況下,您有16位對齊方式,並且直接在奇數地址上訪問c可能會導致麻煩。

但是,您可以使用pack pragma(或其他編譯器具有的選項)強制關閉對齊。

問題是爲什麼。如果你依賴這一點 - 你會讓你的程序在各種體系結構上不可移植和不可預測。

0

你可以強制對齊與編譯:

#pragma pack(push, 1) 
struct X 
{ 
    short a; 
    char b; 
}; 
#pragma pack(pop) 

這是微軟的C++編譯器支持。我不知道這是否是一種便攜式的執行方式。

+0

只有當我控制了X的定義時纔有效,對吧? – fredoverflow

+2

由於#pragma是一個預處理器命令,它將被設置爲持續時間,這意味着如果X位於不受控制的頭文件中,則可以在應用此選項之前將其包含,並且該頭文件中的所有項都將打包到一個1字節的邊界。但是,如果您不擁有X,那麼就會提出更多關於您是否應該這樣做的問題。 – Chad

+1

@Chad:在頭部使用'#pragma pack'是非常危險的(現有的編譯代碼可能完全不會這樣,你需要在另一側重新編譯。 –

0

gcc中,您可以使用__attribute__((packed))關鍵字來聲明您的結構,以便保持特定的字節對齊或填充。

因此,舉例來說,你可以不喜歡

typedef struct X 
{ 
    short a; 
    char b; 
} __attribute__((packed)) X; 

typedef struct Y 
{ 
    X x; 
    char c; 
} __attribute__((packed)) Y; 

現在sizeof(Y)將是4個字節......唯一的問題是,你將付出性能損失,需要爲了做任何拆包以滿足硬件平臺的字節對齊要求。

+0

只有當我能控制X的定義時纔有效,對吧? – fredoverflow

+0

是的,它似乎確實如此...一旦你聲明瞭X,你就不能使用另一個'typedef'重新定義它的對齊方式。 – Jason

0

是的,但它不是標準的C/C++,需要特定於編譯器的擴展。對於MSVC,使用pack pragma

#pragma pack(push, 1) 
struct X 
{ 
    ... 
}; 
#pragma pack(pop) 

對於GCC,使用packed type attribute

struct __atribute__((packed)) X 
{ 
    ... 
}; 

隨着一些預處理宏和__pragma token,你可以在這兩種編譯器定義的工作,而不需要一堆#if條件。

+0

只有當我能控制X的定義時纔有效,對吧? – fredoverflow