__packed 结构与单个 __packed 字段

10 篇文章 0 订阅

对于一个ARM系统来说,32位数据如int的访问必须是4字节对齐的,16位就要2字节对齐(struct 结构中都是int16_t,int32_t可不需要添加__packed,如果有偶数个char型也可以不添加,因为可以按半字对齐,如str中有5个char型,不加则为6,加则为5,但也破坏了边界对齐的形态,会增加读取效率),否则就会有Data-Abort的异常。因此在一个struct当中,并不能保证如果按照正常顺序写下来,这些变量就一定是对齐的。例如struct a { char a; int b;};那么b如果紧跟着a,就不会是4字节对齐的。编译就对于这些没有对齐的重新安排他们的顺序使得他们按要求对齐。

5.5.4. __packed 结构与单个 __packed 字段

优化已压缩的 struct 时,编译器尝试推算每个字段的对齐以改善访问。 但是,编译器并非总是可以推算 __packed struct 中每个字段的对齐。 与之相对的是,将 struct 中的单个字段声明为 __packed 时,可以确保对 struct 中自然对齐成员的快速访问。 因此,需要使用压缩结构时,建议您始终压缩结构中的单个字段,而不是整个结构本身。

Note

将 struct 的单个未对齐字段声明为 __packed 还具有其他的优点:程序员可以更清楚的看出 struct 的哪些字段没有对齐。

有关不压缩 struct、压缩整个 struct 和压缩 struct 的单个字段三者之间的差别,将使用Table 5.10 中显示的三个 struct 的执行来加以说明。

在第一个执行中,struct 没有压缩。 在第二个执行中,将整个结构 mystruct 限定为 __packed。 在第三个执行中,从 mystruct 结构中删除了__packed 属性,并且将单个未对齐字段声明为 __packed

Table 5.10. 未压缩 struct、压缩的 struct 和具有单独压缩字段的 struct 的 C 代码

未压缩 struct __packed struct __packed 字段
struct foo
{
    char one;
    short two;
    char three;
    int four;
} c;
__packed struct foo
{
    char one;
    short two;
    char three;
    int four;
} c;
struct foo
{
    char one;
    __packed short two;
    char three;
    int four;
} c;

Table 5.11 是编译器为Table 5.10 中的每个示例实现生成的机器代码的反汇编,其中,每个实现的 C 代码均使用选项 -O2 进行了编译。

Note

-Ospace 和 -Otime 编译器选项控制对未对齐元素的访问是内联进行还是通过函数调用。 使用 -Otime 将导致内联未对齐访问,而使用 -Ospace则导致调用函数来进行未对齐访问。

Table 5.11. 未压缩 struct、压缩的 struct 和具有单独压缩字段的 struct 的反汇编

未压缩 struct __packed struct __packed 字段
; r0 contains address of c
; char one
LDRB    r1, [r0, #0]
; short two
LDRSH   r2, [r0, #2]
; char three
LDRB    r3, [r0, #4]
; int four
LDR     r12, [r0, #8]
; r0 contains address of c
; char one
LDRB  r1, [r0, #0]
; short two
LDRB  r2, [r0, #1]
LDRSB r12, [r0, #2]
ORR   r2, r12, r2, LSL #8
; char three
LDRB  r3, [r0, #3]
; int four
ADD   r0, r0, #4
BL    __aeabi_uread4
; r0 contains address of c
; char one
LDRB  r1, [r0, #0]
; short two
LDRB  r2, [r0, #1]
LDRSB r12, [r0, #2]
ORR   r2, r12, r2, LSL #8
; char three
LDRB  r3, [r0, #3]
; int four
LDR   r12, [r0, #4]

Table 5.11 的未压缩 struct 的反汇编中,编译器始终访问位于对齐字或半字地址上的数据。 编译器可以执行此操作是因为填充了 struct,因此 struct 的每个成员均位于自然大小边界上。

Table 5.11 中的 __packed struct 反汇编中,缺省情况下,字段 one 和 three 在其自然大小边界上对齐,因此编译器可以进行对齐访问。 对可以将其标识为对齐的字段,编译器始终执行对齐字或半字的访问。 对于未对齐字段 two,编译器使用多重对齐内存访问 (LDR/STR/LDM/STM),与固定移位和屏蔽组合在一起,用于访问内存中的正确字节。 编译器调用 AEABI 运行时例程 __aeabi_uread4 以读取未知对齐的无符号字,从而访问字段 four,原因为无法确定该字段是否位于其自然大小边界上。

Table 5.11 中具有单独压缩字段的 struct 的反汇编中,对字段 onetwo 和 three 的访问方式,与在将整个 struct 限定为 __packed 时的访问方式相同。 但是,与压缩整个 struct 的情况相反,编译器对字段 four 进行字对齐访问,因为结构中的 __packed short 的存在可以帮助编译器确定字段 four 位于其自然大小边界上。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值