2009-11-05 127 views
0

所以,我編碼一些數據包結構(以太網,IP等),並注意到其中一些屬性((packed)),它阻止gcc編譯器嘗試向其添加填充。這是有道理的,因爲這些結構應該走上電線。數據結構對齊

但後來,我算的話:

struct ether_header 
{ 
    u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ 
    u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ 
    u_int16_t ether_type;    /* packet type ID field */ 
} __attribute__ ((packed)); 

這是從一個網站複製,但我的代碼也使用2 uint8_t和1個uint16_t。這增加了兩個字(4字節)。

根據來源不同,系統更喜歡按照4,8或甚至16位的倍數對齊結構。所以,我不明白爲什麼屬性((packed))是必要的,因爲afaik不應該打包。

此外,爲什麼雙括號((包裝))爲什麼不使用一對?

回答

5

如果你的結構已經是正確尺寸的倍數,那麼不是,__attribute__((packed))不是必須的,但它仍然是一個好主意,以防你的結構尺寸因任何原因而發生變化。如果您添加/刪除字段,或者更改ETH_ALEN,那麼您仍然需要__attribute__((packed))

我相信需要雙括號才能使代碼與非gcc編譯器兼容。通過使用它們,您可以這樣做:

#define __attribute__(x) 

然後,您指定的所有屬性都將消失。額外的圓括號表示只有一個參數傳遞給宏(而不是一個或多個),而不管您指定了多少個屬性,並且編譯器不需要支持可變宏。

+0

我忘了uint8_t是數組;愚蠢的我,但良好的呼籲計劃改變。 – mamidon 2009-11-05 03:22:23

2

儘管您的系統可能更喜歡某種特定的對齊方式,但其他系統可能不會。即使__attribute__((packed))沒有效果,這是一個很好的偏執狂。

至於爲什麼它是雙括號,這個GCC特定的擴展需要雙括號。單括號會導致錯誤。

+0

優秀點。考慮一個64位或未來的128位系統。 – 2009-11-05 03:41:46

0

packed指的是填充/對齊裏面的的結構,而不是結構的對齊方式。例如

struct { 
    char x; 
    int y; 
} 

大多數編譯器將分配的Y偏移4,除非你聲明爲包裝的結構(在這種情況下,y將得到在1偏移分配)。

+1

使用打包在這樣的結構上是一個非常糟糕的想法,因爲對y的訪問將陷入一些平臺。 – 2009-11-05 13:22:08

+1

更一般地說,取決於C結構來表示獨立於平臺的數據佈局正在尋求麻煩。包裝只是爲另一個交易一個麻煩。 – 2009-11-05 15:06:46

1
 
in win32, you can do like this: 
#pragma pack(push) //save current status 
#pragma pack(4)//set following as 4 aligned 
struct test 
{ 
char m1; 
double m4; 
int m3; 
}; 
#pragma pack(pop) //restore 
+0

這些編譯指令也適用於GCC。 – 2009-11-05 03:42:27

0

對於這種結構,即使ETH_ALEN是奇數,你有他們兩個,所以UINT16變量將neccessarily是在兩個或零字節偏移,而打包不會做任何事情。取決於打包是可移植性的一個壞主意,因爲打包機制是不可移植的,並且如果使用它們,則可能必須將字節拷入進和出成員變量,以避免此問題所針對的平臺上的未對齊異常。