__packed引起的问题

origin: http://bbs.csdn.net/topics/300096265

在ARM core的平台(StrongARM, 2410, XScale)上,如果企图通过一个独立的指针对某个数
据结构的内部成员域进行定位和访问时,会遇到下面的问题(注,在IA-32 X86平台不会出现
这样的问题)。

定义一个数据结构:
struct __attribute__((packed)) test {
char c; // 1个字节
short s; // 2个字节
long l; // 4个字节
} st;

packed属性,对应于gcc编译选项 -fpack-struct;

test的内存布局在该属性的制约下是紧凑的,也就意味着第2、3个成员s、l的起始地址将是
奇地址。

如果另行定义一个独立指针: unsigned long t;
通过“t+偏移字节数”的方式来定位(访问)结构内成员域,则会在强制类型转换t指针来赋值
或者读取相应成员域时,出现下面的问题:
(假定该结构的起始地址为A0, 则c、s、l的地址各为A0、A1、A3)

1. 编译器版本(arm version):GCC 2.95.2 / 3.2 / 3.3.2
t = (unsigned long) &st;
*((short*)(t+1)) = 0x0201;
期望: 0x01赋于A1字节, 0x02赋于A2字节
实际: 0x01赋于A0字节, 0x02赋于A1字节,与期望不吻合

*((long*)(t+3)) = 0x08070605;
期望: 0x05 - 0x08 逐次赋于 A3 - A6 字节
实际: 0x05 - 0x08 逐次赋于 A0 - A3 字节,与期望不吻合

结论: 基于这些GCC版本,如果对奇地址进行强制类型转换,企图获得"字、双字"的数据类型,
则强制转换后所获得的数据类型,其地址将被自动"优化"为最近的可被相应对齐模数
(字型数据的对齐模数是2,双字的是4)整除的低位偶地址!

2. 编译器版本(arm version):GCC 2.95.3 / 3.0
t = (unsigned long) &st;
*((short*)(t+1)) = 0x0201;
期望: 0x01赋于A1字节, 0x02赋于A2字节
实际: 0x01赋于A1字节, 0x02赋于A2字节,与期望吻合

*((long*)(t+3)) = 0x08070605;
期望: 0x05 - 0x08 逐次赋于 A3 - A6 字节
实际: 0x05 - 0x08 逐次赋于 A0 - A3 字节,与期望不吻合

结论: 基于这些GCC版本,如果对奇地址进行强制类型转换,企图获得"双字"的数据类型,
则强制转换后所获得的数据类型,其地址将被自动"优化"为最近的可被相应对齐模数
4整除的低位偶地址!但对字型数据的此类操作,却不会引起这种指针优化。


附,有资料称:
某些架构上访问数据时有对齐的要求,比如只能从4字节边界上读取一个4字节的数据类型。
IA-32架构没有硬性要求对齐,尽管未对齐的访问降低执行效率。另外一些架构,比如MIPS、
SPARC、m68k、ARM(<V3),要求对齐访问,否则向当前进程分发SIGBUS信号,主要是相对早
期的RISC CPU存在此问题。

那么有没有一个办法(比如gcc的编译选项,或者一个__attribute__),能制约上述的这种指针优化,
使其不自动发生!从而使实际操作与期望操作相吻合?

进一步地问,为何不同版本的arm-linux-gcc所编译出的执行码的在这个问题上的表现不一样!?
这后面有更深层的理论背景吗?

================
如果endian是确定的,我喜欢这样的形式:((unsigned char*)&s)[0] * 256 + ((unsigned char*)&s)[1] 
=============================
en,这样把操作分解成基于字节的处理确实是一个变通的办法,和本人的考虑是一致的;在找不出更好解决方法的情况下,我认为可以有下面3种办法来回避这样的问题:
1. 改变数据源的结构布局,放弃紧凑布局;
代价:增加并浪费了 padding 字节,且既有应用需要重写,以配合结构体内存布局的变化;
2. 改变对结构成员的访问方式,放弃通过独立指针来定位/读写成员域,而直接采用成员名的方式访问;
代价:既有应用程序的改动范围较大;
3. 维持目前的数据源和数据访问方式,而新增一个过渡层,表现形式可以是一组宏,或者内联函数,或
者函数,对结构体内的一切字或双字型数据的访问,通过这个过渡逻辑被分拆为以字节为基础的操作,
从而回避指针强制类型转换时发生优化;这也同样是nxin的思路!
代价:既有应用程序在访问结构体成员时的代码形式发生变化,但个人认为这种方法对系统整体代码的
影响是最小的。

可是变通归变通,欢迎大家继续对可能根本解决此问题的方法进行讨论!谢谢!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值