【转】__attribute__((packed)) 指针传递,赋值错误问题。 - Linux/Unix社区 / 程序开发区

来源:百度文库 编辑:神马文学网 时间:2024/04/29 02:09:09
  • xulinguestc
  • (凌云)

  • 等 级:
  • 结帖率:

楼主发表于:2009-03-02 15:53:48 各位大侠, 外部打印值,和内部赋的值,完全不一样,为什么呢,怎么解决? 请看下面的程序。

程序:
===========================
typedef struct AUTO_SUBMIT_ST
{
char cAutoSubmitFlag; // 自动上报开关
unsigned int uiStartTime; // 开始时间
unsigned int uiEndTime; // 结束时间
unsigned int uiTimeCycle; // 周期时间
unsigned int uiLastTime; // 上一次上报时间
}__attribute__((packed))AutoSubmitInfo; // 自动上报信息结构体


void testfun(unsigned int * output, unsigned short input)
{
 *output=(unsigned int )input;//函数内 部赋值 
 printf("%x=%x\n",output,*output);
 printf("%x ",*((char*)output+0));printf("%x ",*((char*)output+1));printf("%x ",*((char*)output+2));printf("%x \n",*((char*)output+3));
}
int main(int argn, char *argc)
{
 AutoSubmitInfo testdata;
AutoSubmitInfo* pst=&testdata;

 testfun(&(pst->uiLastTime), 0xbc);

 printf("%x=%x\n",&(pst->uiLastTime),pst->uiLastTime);//外部打印值,和内部赋的值,完全不一样,为什么呢,怎么解决? printf("%x ",*((char*)(&(pst->uiLastTime))+0));printf("%x ",*((char*)(&(pst->uiLastTime))+1));printf("%x ",*((char*)(&(pst->uiLastTime))+2));printf("%x \n",*((char*)(&(pst->uiLastTime))+3));
}
===========================
编 译:
[root@localhost MIT]# arm-linux-gcc test.c
===========================
打 印结果:
[/mnt/nfs]./a.out 
内部bffffe59=bc000000
0 0 0 a4  
外 部bffffe59=a4000000
0 0 0 a4 


  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
回复次数:9
  • white1977
  • (天堂)

  • 等 级:

#1楼 得分:0回复于:2009-03-02 16:06:41 我在redhat9.0 系统中测试你的程序,打印的值是一样的。
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
精华推荐:如何使LINUX机器CPU使用率为 100%的办法。
  • xulinguestc
  • (凌云)

  • 等 级:

#2楼 得分:0回复于:2009-03-02 16:19:00 我是在arm板子上跑的,所以用arm-linux-gcc编译。 pc上跑是没有问题的。
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
精华推荐:文件系统ext2的一些不理解
  • white1977
  • (天堂)

  • 等 级:

#3楼 得分:0回复于:2009-03-02 16:31:35 char cAutoSubmitFlag; // 自动上报开关 
你把这个定义成int型 试试。

  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
精华推荐:急救:pthread多线程问题。
  • xulinguestc
  • (凌云)

  • 等 级:

#4楼 得分:0回复于:2009-03-02 16:43:45 天堂,你好! 改成int是正常了,但是结构体里不能只有int型啊, 还是不能彻底解决这个问题。
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
精华推荐:shell程序、fork()函数、 execve()函数之间什么关系?
  • white1977
  • (天堂)

  • 等 级:

#5楼 得分:0回复于:2009-03-02 17:05:23 这应是字节对齐问题。不用指针的方式你再试试。
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
精华推荐:ldapsearch获取的值,如果有中文 如何处理
  • xulinguestc
  • (凌云)

  • 等 级:

#6楼 得分:0回复于:2009-03-03 08:40:53 就是想用指针啊, 方便。 不知道怎么解决这个问题,哪位大侠有好办法可以解决?!
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
  • white1977
  • (天堂)

  • 等 级:

#7楼 得分:0回复于:2009-03-03 09:27:26 那你就用结构指针试试。
typedef struct AUTO_SUBMIT_ST 

char cAutoSubmitFlag; // 自动上报开关 
unsigned int uiStartTime; // 开始时间 
unsigned int uiEndTime; // 结束时间 
unsigned int uiTimeCycle; // 周期时间 
unsigned int uiLastTime; // 上一次上报时间 
}__attribute__((packed))AutoSubmitInfo; // 自动上报信息结构体 


void testfun(AutoSubmitInfo * output, unsigned short input) 

output->uiLastTime=(unsigned int )input;//函数内部赋值 

int main(int argn, char *argc) 

AutoSubmitInfo testdata; 
AutoSubmitInfo* pst=&testdata; 

testfun(pst, 0xbc); 

你可以找一些关于参数指针方面的资料看看。
  • 对我有用[0]
  • 丢个板砖[0]
  • 引用
  • 举报
  • 管理
  • TOP
  • xulinguestc
  • (凌云)

  • 等 级:

#8楼 得分:0回复于:2009-03-03 09:54:13 好像没有办法解决这个问题, 其他地方找了个文章看了。

http://www.linuxforum.net/forum/showflat.php?Cat=&Board=embedded&Number=535938
在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(期的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]
  • 引用
  • 举报
  • 管理
  • TOP
  • cdqy
  • (触电)

  • 等 级:

#9楼 得分:0回复于:2009-09-03 11:37:06 我也遇到类似的问题.
typedef struct {
unsigned char flag; //有效性
int baudrate; //速率
unsigned char serial_num; //端口号
unsigned char parity; //校验
unsigned char sync_mode; //同步方式
unsigned char rtscts; //流控制
unsigned char bytesize; //数据位长度
unsigned char stopbits; //停止位长度
}__attribute__((packed)) S_COMM_PARA;

结 果在对这个结构数组赋值时出现了问题
int i;
S_COMM_PARA com_para[2];

for ( i=0; i<2; i++ )
{
  com_para[i]. baudrate = 9600;
  com_para[i]. bytesize = 8;
  printf("com_para[%d].bytesize=%d\n", i, com_para[i]. bytesize );
  printf("i=%d, com_para0].bytesize=%d\n", i, com_para[0]. bytesize );

}

结 果实际打印的是在第二次循环后,com_para[0].bytesize = 2;
【转】__attribute__((packed)) 指针传递,赋值错误问题。 - Linux/Unix社区 / 程序开发区 用dlopen和dlsym得到的函数指针,在dlclose后还能继续使用么? - Linux/Unix社区 / 程序开发区 用GCC将源文件编译成库文件的问题 Linux/Unix社区 / 程序开发区 用GCC将源文件编译成库文件的问题 Linux/Unix社区 / 程序开发区 用GCC将源文件编译成库文件的问题 Linux/Unix社区 / 程序开发区 - CSDN社区 community.csdn.net Makefile一问:如何修改.o输出文件的输出路径 Linux/Unix社区 / 程序开... 问下关于put_user问题 - Linux/Unix WebFldrs XP 是什么程序? - 免费软件,绿色软件,linux/unix/win... linux?下c?程序?段错误?分析 ChinaUnix.net - 写给Linux内核新手-关于Linux内核学习的误区 - 中国Unix技术社区 linux中到底有多少个系统空间堆栈?? Linux/Unix社区 / 内核及驱动程序研究... Linux系统下C语言编程基础知识介绍 - Linux/Unix社区 / 实用资料发布区 论坛首页 - 中国最大的Linux/Unix技术社区 - IT人的网上社区 - bbs.C... 重视linux/unix Linux/Unix patch用法 - LINUX/UNIX - boisheng -- Linux笔记 解决linux下java程序(例如applet)中文乱码问题 应用 Valgrind 发现 Linux 程序的内存问题 应用 Valgrind 发现 Linux 程序的内存问题 嵌入式汇编中divl的用法? Linux/Unix社区 / 内核及驱动程序研究区 解决基于tomcat的web应用乱码问题 - J2EE开发者 - web思想社区 关注互联网平台级架构设计,UNIX/LINUX系统管理,项目管理,个人职业规划及RIA,CSS/JS/XML,ASP, 段错误(Segment Fault!)莫名的问题|程序编程 关于指针的问题? 如何安装SUN公司的SOLARIS操作系统------(unix)50分呀!!! Linux/Unix社区 / 系统维护与使用区 - CSDN社区 community.csdn.net 指向指针的指针的一个问题