2009-11-05 95 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是在两个或零字节偏移,而打包不会做任何事情。取决于打包是可移植性的一个坏主意,因为打包机制是不可移植的,并且如果使用它们,则可能必须将字节拷入进和出成员变量,以避免此问题所针对的平台上的未对齐异常。