2014-11-25 79 views
1

我讀這樣的回答:C struct memory layout?並很想知道爲什麼:爲什麼這個結構不正確對齊?

struct ST 
{ 
    long long ll; 
    char ch2; 
    char ch1; 
    short s; 
    int i; 
}; 

仍然是24個字節而不是16,我期待2 *字符+短+ INT以適應8個字節大小。爲什麼這樣?

編輯:

很抱歉的混亂,我在64位系統上運行(Debian的)GCC(Debian的4.4.5-8)4.4.5。我已經知道它是由於填充。我的問題是爲什麼?答案之一提示:

char = 1 byte 
char = 1 byte 
short = 1 byte (why is this 1 and not 2?) 
* padding of 5 bytes 

我的問題是,爲什麼是這樣的填充這裏...爲什麼不只是把一個INT後直短,它仍然會適合8個字節內。

+2

你在64位系統上檢查這個嗎?您還可以檢查成員的偏移量,以查看它們最終使用['offsetof'](http://en.cppreference.com/w/c/types/offsetof)宏的位置。關於標題中的措辭,編譯器選擇的對齊對於您的系統來說肯定是「合適的」。 – 2014-11-25 13:01:12

+0

由於填充。 – bitcell 2014-11-25 13:02:42

+3

什麼是「64位系統」?什麼是硬件架構?在x86_64 ABI上,該結構的大小應爲16個字節。我在Ubuntu,MacOS,OpenBSD和Centos上進行了驗證。它不依賴於編譯器,所以編譯標誌有些問題,或者你正在使用alpha或者其他奇怪的東西。 – Art 2014-11-25 14:12:29

回答

1

簡單的答案是:它不是24字節。或者你正在運行Linux的64位s390端口,我還沒有找到ABI文檔。 Debian可以運行的每個其他64位硬件都將這個結構的大小設置爲16個字節。

我已經挖出了ABI文檔一羣不同CPU的ABI的,他們都有或多或少的這種措辭(看來他們都已經相互複製):

結構和聯合承擔對齊最嚴格對齊的組件。每個成員都分配到具有適當對齊的最低可用偏移量。任何對象的大小總是對象的對齊的倍數。

而且我發現所有架構ABI文檔(MIPS64,PPC64,AMD64,IA64,SPARC64,arm64)具有用於焦炭1對準,短2,INT 4和長長8.

即使操作系統允許自己製作ABI,幾乎每個類Unix系統,特別是Linux都遵循System V ABI及其補充的CPU文檔,這些文檔很好地說明了這種行爲。而Debian絕對不會改變這種行爲與所有其他Linux的不同。

這裏有一個快速驗證(全部在AMD64/x86_64的這就是你最有可能運行):

$ cat > foo.c 
#include <stdio.h> 

int 
main(int argc, char **argv) 
{ 
    struct { 
     long long ll; 
     char ch2; 
     char ch1; 
     short s; 
     int i; 
    } foo; 

    printf("%d\n", (int)sizeof(foo)); 
    return 0; 
} 

的MacOS:

$ cc -o foo foo.c && ./foo && uname -ms 
16 
Darwin x86_64 

Ubuntu的:

$ cc -o foo foo.c && ./foo && uname -ms 
16 
Linux x86_64 

CentOS:

$ cc -o foo foo.c && ./foo && uname -ms 
16 
Linux x86_64 

OpenBSD系統:

$ cc -o foo foo.c && ./foo && uname -ms 
16 
OpenBSD amd64 

還有別的東西錯了你的編譯。或者那不是你正在測試的結構,或者你正在一個非常奇怪的硬件架構上運行,並將其指定爲「64位」,相當於說「我駕駛的是政府頒發的車輛,並且它具有非常奇怪的加速和引擎5分鐘後切斷「,並沒有提到你在談論航天飛機。

0

通常爲了最大限度地減少填充,通常的做法是從最大到最小的順序排列成員,你可以嘗試對它們進行重新排序,看看會出現什麼結果?

struct ST 
{ 
    long long ll; //8 bytes 
    int i;   //4bytes 
    short s;  //2 bytes 
    char ch2;  //1 byte 
    char ch1;  //1 byte 
}; 

一共是16個字節

+0

請檢查我的編輯,我使用的是debian 64bit,gcc不是g ++ – sprocket12 2014-11-25 13:12:16

1

這是所有關於填充。在visual studio(以及其他一些編譯器)中,您可以使用#pragma push/pack使其與您想要的一致。

#pragma pack(push, 1) 
struct ST 
{ 
    /*0x00*/ long long ll; 
    /*0x08*/ char ch2; 
    /*0x09*/ char ch1; 
    /*0x0a*/ short s; 
    /*0x0c*/ int i; 
    /*0x10*/ 
}; 
#pragma pack(pop) 

既然你說,這是即將到來的大小爲24,我要去猜測編譯器在4個字節對齊,你做這樣的事情:

struct ST 
{ 
    /*0x00*/ long long ll; 
    /*0x08*/ char ch2; 
    /*0x09*/ char padding1[0x3]; 
    /*0x0c*/ char ch1; 
    /*0x0d*/ char padding2[0x3]; 
    /*0x10*/ short s; 
    /*0x11*/ char padding3[0x2]; 
    /*0x14*/ int i; 
    /*0x18*/ 
}; 

(對不起,我在做這種事情的時候用十六進制表示,0x10是16進制,0x18是24進制。)

+0

哪個CPU ABI會指定這種奇怪的對齊和填充?即使是沒有指令來訪問一個或兩個字節值的字母,也需要4個字節的短路對齊。 – Art 2014-11-25 15:44:50