2009-10-08 57 views
3

如果我定義一個char變量尺寸的結構和相應的可變

char a; 

和具有單焦構件

struct OneChar { 
char a; 
}; 

這些都定義將具有「焦炭」的中的所有尺寸的結構編譯器? 我的疑問是,如果我們在結構中定義一個char變量,由於內存打包,它會佔用比char大小更多的大小嗎?

+0

我的實際疑問是,在單個成員結構中,內存填充是否會起作用? – Byju 2009-10-08 17:33:20

回答

6

它取決於體系結構和編譯器。對於這種特殊情況,您應該安全,但請檢查Data Structure Padding

下面是一個excerpt

在x86 C結構的典型對準

數據結構成員都存儲 順序在存儲器中,使得在 的構件數據1下方的結構 將總是在Data2和Data2之前將始終存在Data3:

struct MyData 
{ 
    short Data1; 
    short Data2; 
    short Data3; 
}; 

如果類型「短」被存儲在存儲器的兩個 字節然後 以上 所示的數據結構中的每個成員將是2字節對齊。 Data1將 置於偏移量0處,將數據2置於偏移量2處,並將數據3置於偏移量4處。該 結構的大小將爲6字節。

的類型 結構的每個成員的通常具有默認 對準,這意味着它會, 除非 程序員另有要求,被一個 預先確定的邊界上對齊。

  • 一個char(一個字節)爲1字節對齊的:在編譯爲32位x86時,以下 典型比對是有效的來自Microsoft,Borland公司,和 GNU 編譯器。
  • 短(兩個字節)將是2字節對齊。
  • int(四個字節)將以4字節對齊。
  • 浮點數(四個字節)將以4字節對齊。
  • 雙字節(八字節)將在Windows上以8字節對齊,在Linux上以4字節對齊。

這裏是 各類成員的結構,前 彙編共計8個字節:

struct MixedData 
{ 
    char Data1; 
    short Data2; 
    int Data3; 
    char Data4; 
}; 

編譯後的數據結構 將被補充有填充 字節,以確保正確的對準 其每個成員:

struct MixedData /* after compilation */ 
{ 
    char Data1; 
    char Padding0[1]; /* For the following 'short' to be aligned on a 2 byte boundary */ 
    short Data2; 
    int Data3; 
    char Data4; 
    char Padding1[3]; 
}; 

編譯後的si結構的現在是 現在12個字節。需要注意的是 最後一個成員填充了 需要的字節數符合最大類型的 結構。在這種情況下,3個字節是 添加到最後一個成員,以填充 結構爲長字的大小。

它可以改變結構的對準 以減少他們所需要的存儲器 通過改變 編譯器的取向(或「包裝」)的結構 成員(或符合的 現有格式)。

請求所述MixedData 結構上方對準以一個 字節邊界將具有編譯器 丟棄預先確定的對準成員 和沒有填充字節 將被插入。

雖然是 限定結構 構件的取向沒有標準的方式,一些編譯器使用#pragma 指令,以指定內 源文件打包。下面是一個例子:

#pragma pack(push) /* push current alignment to stack */ 
#pragma pack(1)  /* set alignment to 1 byte boundary */ 

struct MyPackedData 
{ 
    char Data1; 
    long Data2; 
    char Data3; 
}; 

#pragma pack(pop) /* restore original alignment from stack */ 

這種結構將具有編譯 大小爲6個字節。上述指令 可從 Microsoft,Borland,GNU和其他許多 編譯器中獲得。

+0

我的疑問是,在單個成員結構中,內存填充是否會起作用? – Byju 2009-10-08 17:32:25

+0

在你的情況下,我不這麼認爲,但正如我之前所說,這取決於。 – Jacob 2009-10-08 17:50:16

1

只要有一個成員,我認爲你是安全的假設。

0

所有a s將具有相同的大小,無論他們是獨立的還是內部的結構。

結構內可能發生的情況是成員之間存在填充......但這也可能發生在「獨立」變量中。

+0

也可以在最後一個成員之後進行填充(不只是成員之間)。 – caf 2009-10-08 21:35:29

0

當你得到一個結構體的大小時,它包含了填充字節。但是,如果您有類似以下內容:

void fun() 
{ 
    char c; 
    int n; 
} 

編譯器可以自由插入它認爲不管是什麼原因填充。所以,在獨立變量的情況下,填充可以在那裏,在結構的情況下,你就不會知道這種情況。

1

您列出的案例將打包爲所有我知道的ABI下的1字節結構。

但如果需要可移植處理更復雜的情況下,最好的做法是,當你需要通過像一招計算地址總是使用sizeof(struct OneChar)計算內存大小時,並採取現場地址的偏移:

(char*)&(((struct OneChar*)0)->a) - (char*)0 
+0

我認爲結構中的第一個字段必須位於偏移量0處。另外,''中的'offsetof'會執行那個可怕的空指針技巧,因此您不必這樣做。 – 2009-10-08 17:26:57

0

各種編譯器將優化以在結構之間或結尾添加填充。所以,在所有的編譯器或平臺上假設分配的大小看起來並不安全。檢查您的編譯器選項以設置struct padding。

例如,Visual Studio使用#pragma pack指令來覆蓋默認優化。