2016-07-08 43 views
2

我在调试下面的代码片段来分析结构成员的字节对齐。使用属性对齐时的内存对齐(1)

#include <stdio.h> 
#include <stdint.h> 
#include <string.h> 

struct v_hdr { 
    uint16_t vlan_tci; 
    uint16_t eth_proto; 
}__attribute__((aligned(1))); 

struct esp_hdr { 
    uint32_t fpa_esp_spi; 
    uint32_t fpa_esp_sequenceid; 
}__attribute__((aligned(1))); 

struct f_cookie { 
    uint16_t vlan_ports; 
    uint16_t untagged_vlan_ports; 
    struct v_hdr vlan_hdr; 
    uint16_t tcp_flags; 
    uint32_t *eth_hdr; 
    uint32_t *ipv4_hdr; 
    struct esp_hdr esp; 
}__attribute__((aligned(1))); 

struct metadata { 
    struct f_cookie flow_cookie; 
} __attribute__((aligned(1))); 

int main() 
{ 
    struct metadata meta; 
    memset (&meta, 0, sizeof(struct metadata)); 

    /* 16 */ meta.flow_cookie.vlan_ports    = 0xffff; 
    /* 16 */ meta.flow_cookie.untagged_vlan_ports = 0xffff; 
    /* 16 */ meta.flow_cookie.vlan_hdr.vlan_tci  = 0xffff; 
    /* 16 */ meta.flow_cookie.vlan_hdr.eth_proto  = 0xffff; 
    /* 16 */ meta.flow_cookie.tcp_flags    = 0xffff; 
    /* 32 */ meta.flow_cookie.eth_hdr    = 0xffffffff; 
    /* 32 */ meta.flow_cookie.ipv4_hdr    = 0xffffffff; 
    /* 32 */ meta.flow_cookie.esp.fpa_esp_spi  = 0xffffffff; 
    /* 32 */ meta.flow_cookie.esp.fpa_esp_sequenceid = 0xffffffff; 

    return 0; 
} 

这里是gdb的X转储return语句之前 -

(gdb) p sizeof meta 
$2 = 40 

(gdb) x/40bt &meta 
0x7fffffffe2d0: 11111111  11111111  11111111  11111111  11111111  11111111  11111111  11111111 
0x7fffffffe2d8: 11111111  11111111  00000000  00000000  00000000  00000000  00000000  00000000 
0x7fffffffe2e0: 11111111  11111111  11111111  11111111  00000000  00000000  00000000  00000000 
0x7fffffffe2e8: 11111111  11111111  11111111  11111111  00000000  00000000  00000000  00000000 
0x7fffffffe2f0: 11111111  11111111  11111111  11111111  11111111  11111111  11111111  11111111 

我的问题是,为什么meta.flow_cookie.eth_hdrtcp_flags后,在4字节边界放在哪里?即在(0x7fffffffe2d8 + 4)。而meta.flow_cookie.ipv4_hdr不在0x7fffffffe2e0

尽管应用aligned(1)属性,为什么这两个成员都放置在8字节边界? PS。我不想使用属性packed。我只想让成员尽可能与4字节地址对齐。它可以实现吗?

+2

GCC文档明确指出:*对齐的属性只能增加对齐;但你也可以通过指定包装来减少它。*为什么你看到不相信的理由?如果你想完成什么'包装',你为什么不想使用'packed'? – tofro

+0

@tofro:如果是这样的话,为什么'fpa_esp_sequenceid'从4字节地址开始?实际上'元数据'结构在开始时包含几个其他的位域变量。使用打包导致这些变量的未对齐内存访问,导致性能滞后。 – tcpip

+0

如果**不指定'aligned(1)',那么'fpa_esp_sequenceid'对齐如何?我非常怀疑'对齐(1)'does * anything * – tofro

回答

2

引用您的代码的摘录:

/* 16 */ meta.flow_cookie.tcp_flags    = 0xffff; 
/* 32 */ meta.flow_cookie.eth_hdr    = 0xffffffff; 
/* 32 */ meta.flow_cookie.ipv4_hdr    = 0xffffffff; 

你假设meta.flow_cookie.eth_hdrmeta.flow_cookie.ipv4_hdr指针是32位长,你的系统,根据您的gdb转储,没有按”似乎是一个32位架构。请注意,sizeof(uint32_t *)sizeof(uint32_t)不一样。如果由于某些原因,这些值是相同的(在32位架构的情况下),那纯粹是巧合。

指针的大小总是足以容纳属于底层体系结构完整地址空间的任何地址。例如,64位体系结构上的sizeof(uint32_t *)至少需要8个字节(64位长)。

由于您的架构似乎有64位地址空间,因此您为对齐所做的假设是有缺陷的。

+1

谢谢!这清除了我的怀疑。 'uint32_t *'实际上是8个字节,并解释了为什么这些成员需要8个字节。 – tcpip