所以,我正在编写一些数据包结构(以太网,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不应该被打包。
另外,为什么双括号((打包))为什么不使用一对?
答案 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不会做任何事情。打包是一个糟糕的可移植性,因为打包的机制不可移植,如果你使用它们,你可能需要在成员变量中进行字节复制,以避免在这个问题的平台上出现错位异常。