数据结构对齐

时间:2009-11-05 02:56:18

标签: c++ linux gcc networking attributes

所以,我正在编写一些数据包结构(以太网,IP等),并注意到其中一些后跟属性((压缩)),这阻止了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位的倍数对齐结构。所以,我不明白为什么属性((打包))是必要的,因为afaik不应该被打包。

另外,为什么双括号((打包))为什么不使用一对?

5 个答案:

答案 0 :(得分:5)

如果您的结构已经是正确大小的倍数,那么不,__attribute__((packed))并非绝对必要,但如果您的结构大小因任何原因而发生变化,那么它仍然是个好主意。如果您添加/删除字段或更改ETH_ALEN,您仍然需要__attribute__((packed))

我认为需要使用双括号才能使代码与非gcc编译器兼容。通过使用它们,您可以这样做:

#define __attribute__(x)

然后您指定的所有属性都将消失。额外的括号意味着只有一个参数传递给宏(而不是一个或多个),无论您指定了多少属性,并且您的编译器不需要支持可变参数宏。

答案 1 :(得分:2)

虽然您的系统可能更喜欢某些特定的对齐,但其他系统可能不喜欢。即使__attribute__((packed))没有效果,也是一种偏执狂。

至于为什么它是双括号,这个GCC特定的扩展需要双括号。单括号将导致错误。

答案 2 :(得分: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 

答案 3 :(得分:0)

packed指的是结构内部的填充/对齐,而不是结构的对齐方式。例如

struct {
  char x;
  int y;
}

大多数编译器将在偏移量4处分配y,除非您将结构声明为打包(在这种情况下,y将以偏移量1分配)。

答案 4 :(得分:0)

对于这种结构,即使ETH_ALEN是一个奇数,你也有两个,所以uint16变量必然会处于两个或零个字节的偏移量,并且packed不会做任何事情。打包是一个糟糕的可移植性,因为打包的机制不可移植,如果你使用它们,你可能需要在成员变量中进行字节复制,以避免在这个问题的平台上出现错位异常。