搜索
bottom↓
回复: 48

编C又遇困难,一个结构体强制转换成另一结构体,结果是什么?

[复制链接]

出0入0汤圆

发表于 2010-7-5 13:26:31 | 显示全部楼层 |阅读模式
--->  强制转换为另一结构体---->
typedef struct                                                       typedef struct
{osal_event_hdr_t hdr;                                               {osal_event_hdr_t hdr;
uint16 groupId;                                                      byte state;
uint16 clusterId;                                                    byte keys;
afAddrType_t srcAddr;                                               }keyChange_t;
byte endPoint;
byte wasBroadcast;
byte LinkQuality;
byte SecurityUse;                                                   
uint32 timestamp;
afMSGCommandFormat_t cmd;
}afIncomingMSGPacket_t;


注:#define uint8 byte

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2010-7-5 13:27:44 | 显示全部楼层
结果肯定是悲剧。

出0入0汤圆

 楼主| 发表于 2010-7-5 13:27:45 | 显示全部楼层
从头按短的截取?

出0入296汤圆

发表于 2010-7-5 13:29:39 | 显示全部楼层
可以去领餐具了,然后排队领便当

出0入0汤圆

 楼主| 发表于 2010-7-5 13:32:41 | 显示全部楼层
各位大侠直说嘛,我菜得很,承受能力强。到底怎么回事?大不了编译报错

出0入0汤圆

 楼主| 发表于 2010-7-5 13:35:59 | 显示全部楼层
回复【3楼】Gorgon Meducer 傻孩子
-----------------------------------------------------------------------

GM哥,我知道你很强的,求真相~

出0入0汤圆

发表于 2010-7-5 13:36:38 | 显示全部楼层
写个函数传递过去很复杂么?还非得强制转换?

出0入0汤圆

 楼主| 发表于 2010-7-5 13:39:02 | 显示全部楼层
回复【6楼】eggcar 各种杯具
-----------------------------------------------------------------------

这是TI的Z-stack的程序,我读得焦头烂额

出0入0汤圆

 楼主| 发表于 2010-7-5 13:40:47 | 显示全部楼层
考虑到有可能是我错误理解为结构体的强制转换,下面我把原文打一遍。各位稍等

出0入0汤圆

发表于 2010-7-5 13:41:44 | 显示全部楼层
确定是强制转换的??从初中开始写c怎么没记得结构体能强制转换?

出0入0汤圆

 楼主| 发表于 2010-7-5 13:43:22 | 显示全部楼层
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t * MSGpkt;

  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        
        case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;


其中用到的结构体在楼主位已定义过,方便阅读在此定义

typedef struct                                                       typedef struct
{osal_event_hdr_t hdr;                                               {osal_event_hdr_t hdr;
uint16 groupId;                                                      byte state;
uint16 clusterId;                                                    byte keys;
afAddrType_t srcAddr;                                               }keyChange_t;
byte endPoint;
byte wasBroadcast;
byte LinkQuality;
byte SecurityUse;                                                     
uint32 timestamp;
afMSGCommandFormat_t cmd;
}afIncomingMSGPacket_t;

出0入0汤圆

 楼主| 发表于 2010-7-5 13:44:00 | 显示全部楼层
回复【9楼】eggcar 各种杯具
-----------------------------------------------------------------------

就是最后那句

出0入0汤圆

发表于 2010-7-5 13:44:57 | 显示全部楼层
如果不是基类和派生类的关系……

出0入0汤圆

 楼主| 发表于 2010-7-5 13:46:43 | 显示全部楼层
C的精髓就是想写多纠结就能写多纠结

出0入0汤圆

发表于 2010-7-5 13:51:12 | 显示全部楼层
指针啊,state和keys是否各是groupId的一半?

出0入0汤圆

 楼主| 发表于 2010-7-5 13:55:36 | 显示全部楼层
回复【14楼】eggcar 各种杯具
-----------------------------------------------------------------------

长度上是,不过我看逻辑上state+keys和groupId没有关系似乎。按你的线索我再去读读。

出0入0汤圆

发表于 2010-7-5 13:55:47 | 显示全部楼层
应该是state和keys各是groupId的高低八位

出0入0汤圆

发表于 2010-7-5 13:57:30 | 显示全部楼层
回复【15楼】almasy 小陈同学
-----------------------------------------------------------------------

还得看内存怎么分配的了,什么环境上运行?

出0入0汤圆

 楼主| 发表于 2010-7-5 13:57:41 | 显示全部楼层
回复【16楼】eggcar 各种杯具
-----------------------------------------------------------------------

那(keyChange_t *)MSGpkt)->state该怎么理解?是强制转换吗?

出0入0汤圆

 楼主| 发表于 2010-7-5 13:58:02 | 显示全部楼层
回复【17楼】eggcar 各种杯具
-----------------------------------------------------------------------

IARfor51

出0入0汤圆

 楼主| 发表于 2010-7-5 13:59:24 | 显示全部楼层
我也是直觉从最头上开始截取,只好这样先读读看了

出0入0汤圆

发表于 2010-7-5 14:04:10 | 显示全部楼层
回复【18楼】almasy 小陈同学
-----------------------------------------------------------------------

是个指针的强制转换,51我不熟悉,这句应该依赖具体实现

出0入0汤圆

 楼主| 发表于 2010-7-5 14:10:10 | 显示全部楼层
回复【21楼】eggcar 各种杯具
-----------------------------------------------------------------------

感谢大侠的参与!

出0入0汤圆

发表于 2010-7-5 14:47:37 | 显示全部楼层
结构体在SDRAM中是数组形式保存的,
强制转换成另一种数据结构也是数组形式,
只是你访问的变量变了,
而保存在SDRAM中的数组的值本身没有变的;

出0入0汤圆

 楼主| 发表于 2010-7-5 14:55:34 | 显示全部楼层
回复【23楼】EasyEagle
-------------------------------------------------------------------
最主要的影响就是指针每加一时后移的数据位数不同了,是这样理解么?

出0入0汤圆

发表于 2010-7-5 22:01:34 | 显示全部楼层
先讲出你想干什么,再提问.

出0入0汤圆

发表于 2010-7-5 22:23:49 | 显示全部楼层
jihao

出0入296汤圆

发表于 2010-7-5 22:40:08 | 显示全部楼层
to 【10楼】 almasy 小陈同学
给你的代码进行解析:
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )   显然这是一个事件处理函数
{
  afIncomingMSGPacket_t * MSGpkt;                               定义了一个指向消息结构体的指针
  
  if ( events & SYS_EVENT_MSG )                                 检查要处理的事件是不是系统消息
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); 从消息队列里面,根据消息ID获取数据包的首地址。
    while ( MSGpkt )                                            等效于 if (NULL != MSGpkt)
    {
      switch ( MSGpkt->hdr.event )                              检查事件类型
      {
         
        case KEY_CHANGE:                                        按键状态发生了变化
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          这里就是关键的关键。大家要明白,C语言处理数据只关心两件事情:数据的大小和数据的操作方式。
          简单说,数据的大小可以通过结构体本身来限定,也可以通过指定大小的数组来限定,总之,只要占着地方,怎样都无所谓的。
          但是,结构体本身决定了如何“操作”对应的空间,也就是说,对同一个空间,绑定不同的结构体,就可以按照对应的原则来
          操作该段内存。说了这么多废话,简单的说,结构体类型afIncomingMSGPacket_t中第一个元素是一个函数指针,指向一段程序
          这里显然是指向对应消息KEY_CHANGE的处理函数的,结构体keyChange_t第一个元素也是它。这都没有什么好说的。但是,这里
          存储器如何操作取决于绑定的结构体,在随后的state和key上就能看出来了。对结构体afIncomingMSGPacket_t来说是groupId
          这对KEY_CHANGE事件来说显然没有意义,实际上,KEY_CHANGE事件的发送方利用了这个垃圾空间,用它来存储state和key。所
          以实际上,发送方用afIncomingMSGPacket_t的大小来申请空间,以符合消息队列存储所需的基本结构,占用空间以后,用结构
          体keyChange_t来实际存储数据;在上面那段消息处理程序中,判定为KEY_CHANGE事件后,就用keyChange_t来还原数据。

          break;


小陈同学,你需要补充一些指针方面的知识。然后再去看别人的程序。推荐两本书给你,老外的OOC,和中国人的OOPC。希望对你有所帮助,
你可以下载我的PDF( http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3239709&bbs_page_no=1&bbs_id=3039 ) 然后阅读第三篇
的内容(也就是第十一章到第十四章的内容)。

出0入0汤圆

发表于 2010-7-6 00:10:20 | 显示全部楼层
此类用法在消息处理中随处可见,键盘消息,鼠标消息以及通用消息使用相同的结构体声明但是存储不同意义的数据时就是这样子。对客观世界从宏观到微观描述的结果会使得刻画变得愈来愈清晰,当然也会使我们顿失向之所在!
一个口袋,装什么都是装,只有装的人知道。

出0入4汤圆

发表于 2010-7-6 08:17:58 | 显示全部楼层
楼上说得没错,当你按另一种结构体的方式给当前的结构体赋值,那么强制转换成那种结构体之后,就不会有问题。

出0入0汤圆

 楼主| 发表于 2010-7-6 08:31:45 | 显示全部楼层
回复【27楼】Gorgon Meducer 傻孩子
-----------------------------------------------------------------------
做了这么详细的分析,辛苦啦。多谢GM哥!

出0入0汤圆

 楼主| 发表于 2010-7-6 08:35:30 | 显示全部楼层
回复【28楼】sleijun
此类用法在消息处理中随处可见,键盘消息,鼠标消息以及通用消息使用相同的结构体声明但是存储不同意义的数据时就是这样子。对客观世界从宏观到微观描述的结果会使得刻画变得愈来愈清晰,当然也会使我们顿失向之所在!
一个口袋,装什么都是装,只有装的人知道。
-----------------------------------------------------------------------

哥您的言辞意表好有气质啊,呵呵。通俗形象的比喻对小菜鸟的理解是立竿见影滴

出0入0汤圆

发表于 2010-7-6 13:27:09 | 显示全部楼层
struct 大学生{
  吃饭;
  睡觉;
  谈恋受;
};

struct 鸡{
  Ribi;
  Yanshe;
  S69;
};


void * 某女;



if(白天){
   ((struct 大学生 *)(某女))->吃饭 += 2;
   ((struct 大学生 *)(某女))->谈恋爱 += 5;
}

else

if(晚上){
   ((struct 鸡 *)(某女))->Ribi += 10;
   ((struct 鸡 *)(某女))->Do69 += 8;
}

else
{
   ((struct 大学生 *)(某女))->数钱 += 1;
}




以上例子中,"某女"为实际内存实体指向,而"大学生"与"鸡"为两种不同的访问方式,不论使用哪种方式,内存地址不变,但通过不同访问方式,内存为系统提供了不同的应用方式.

出0入264汤圆

发表于 2010-7-6 14:27:36 | 显示全部楼层
回复【32楼】rainyss
struct 大学生{
  吃饭;
  睡觉;
  谈恋受;
};
struct 鸡{
  ribi;
  yanshe;
  s69;
};
void * 某女;
if(白天){
   ((struct 大学生 *)(某女))->吃饭 += 2;
   ((struct 大学生 *)(某女))->谈恋爱 += 5;
}
else
if(晚上){
   ((struct 鸡 *)(某女))->ribi += 10;
   ((struct 鸡 *)(某女))->do69 += 8;
}
else
{
   ((struct 大学生 *)(某女))->数钱 += 1;
}

以上例子中,"某女"为实际内存实体指向,而"大学生"与"鸡"为两种不同的访问方式,不论使用哪种方式,内存地址不变,但通过不同访问方式,内存为系......
-----------------------------------------------------------------------

犀利!

出0入0汤圆

发表于 2010-7-6 15:10:58 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-7-6 15:58:44 | 显示全部楼层
mark

出0入296汤圆

发表于 2010-7-6 16:04:54 | 显示全部楼层
果然是犀利啊……文字果然是苍白的,生活啊,这就是生活的灵感

出0入93汤圆

发表于 2010-7-7 09:58:45 | 显示全部楼层
1、首先,C语言中(不是C++)结构体是不可能强制转换的,否则编译器直接ERROR伺候。只有指针可以强制转换。
2、强制转换时自己应该明确其中每一项成员的含义,否则就会乱套。
   引用【32楼】rainyss所举的例子,除非完全明确自己每一项成员的含义,否则这种方式转换是很要不得的,到最后都不知自己干了啥。在这两个结构体中,吃饭和日B明显不是同一件事,强制转换之后成了什么了?吃饭和日B的总次数?
3、单就事论事,只针对本题而言,对于楼主位的强制转换,使用联合体将更加友好,省得来回折腾指针。如果还有其他用途,那就不是最好的了。
   这样:
typedef struct{
  osal_event_hdr_t hdr;  
  union{                              
    uint16 groupId;
    struct{
      byte state, keys;
    };
  };              
  uint16 clusterId;
  afAddrType_t srcAddr;
  byte endPoint;
  byte wasBroadcast;
  byte LinkQuality;
  byte SecurityUse;                                                   
  uint32 timestamp;
  afMSGCommandFormat_t cmd;
}afIncomingMSGPacket_t;
  当然,需要你的C编译器支持匿名结构,否则还得取个名字。

出0入0汤圆

发表于 2010-7-7 13:03:36 | 显示全部楼层
联合体的名字是很冗长的,一般用于较严谨的场合,而简单场合则通常用强制类型转换了事.

楼上所说的"对结构无法直接作强制类型转换"的问题,在PC上不是个问题,先取指针再转换即可,但在单片机上这种操作有可能大大降低效率,我给一个简单的解决办法:

struct A{int a; int b;}
struct B{int a; int b;}

struct A memA;

下面用B的方式访问memA:

(*(struct B*)(&memA)).a = 1;
(*(struct B*)(&memA)).b = 2;

不知道语句有没写错,反正意思就是这样子.
这种不使用中间指针变量作类型转换的优势在于,直接对结构体访问时,用的是绝对寻址,而对指针进行访问,用的是相对寻址,大家展开汇编去看看性能相差多少就知道了.

对于51之类CPU,在一些性能要求较高或有代码长度要求的场合下,应尽量避免"结构+指针"的用法,有时不得不牺牲一下程序的可读性.

出0入4汤圆

发表于 2010-7-7 19:59:22 | 显示全部楼层
是指针类型的强制转换,没什么问题。指针的实质,只是一个地址,所以可以转换成你所想到的类型,从而使你可以对他进行你所想要的操作。比如指针p=0x10000000,而0x10000000的地址起始存放的是0x12345678,在小端方式下,当p为8位数指针类型时,操作数是0x78,16位数类型时操作数是0x5678,32位数操作类型时,操作数时0x12345678,当为函数指针时,函数起始地址就是0x12345678,当为结构体指针时,0x12345678又是结构体前面几个成员的值。当我把它强制转换成另一个结构体指针时,它又是另一个结构体前面几个成员的值。楼上的比方有点意思,就像有个女人,你和她不认识的时候,你只能看看她,当你是她普通朋友的时候,你可以握握她的手,当你是他男朋友的时候,你就可以亲她,等你做了她老公,你就可以和她OOXX了。但人还是那个人,身体也都在,但以你的类型不同,而可以对她进行不同的操作。

出0入0汤圆

 楼主| 发表于 2010-7-15 09:08:26 | 显示全部楼层
"P1_1=!P1_1"   这句又看不懂了。。。

出0入0汤圆

发表于 2010-7-15 11:29:55 | 显示全部楼层
回复【32楼】rainyss
struct 大学生{
  吃饭;
  睡觉;
  谈恋受;
};
struct 鸡{
  ribi;
  yanshe;
  s69;
};
void * 某女;
if(白天){
   ((struct 大学生 *)(某女))->吃饭 += 2;
   ((struct 大学生 *)(某女))->谈恋爱 += 5;
}
else
if(晚上){
   ((struct 鸡 *)(某女))->ribi += 10;
   ((struct 鸡 *)(某女))->do69 += 8;
}
else
{
   ((struct 大学生 *)(某女))->数钱 += 1;
}

以上例子中,"某女"为实际内存实体指向,而"大学生"与"鸡"为两种不同的访问方式,不论使用哪种方式,内存地址不变,但通过不同访问方式,内存为系......
-----------------------------------------------------------------------

O(∩_∩)O 这回真的明白啊。

出0入0汤圆

发表于 2010-9-27 16:04:00 | 显示全部楼层
强大...学习!

出0入0汤圆

发表于 2010-9-27 16:31:58 | 显示全部楼层
回复【40楼】almasy 小陈同学
"p1_1=!p1_1"   这句又看不懂了。。。
-----------------------------------------------------------------------

LED闪烁,端口位操作,取反

出0入9汤圆

发表于 2010-9-27 16:57:06 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2010-9-27 17:38:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 17:41:04 | 显示全部楼层
看样子32楼是个很有才的人才哦。。。。哈哈哈哈

可以把程序和实际操作联系在一起,
这就是学到了精髓的人才,哈哈哈哈,不是贬义!!!
理论联系实际,才能学以致用啊。

佩服、、佩服、、佩服!!!

出0入0汤圆

发表于 2010-9-27 17:41:57 | 显示全部楼层
强制转换其实只是对某一内存或数据段进行格式化,以另一种格式去访问或操作这段数据,会影响对象的操作及访问方式,如果两个结构体内成员格式都相同,强制转换不会带来任何灾难,即便是两个结构体成员的数据类型及格式完全不同,转换本身也不会给系统带来什么严重后果,但访问结果就要碰运气了,如39楼所说:某女--随机,你想象她是你老婆这完全无罪,但当你以老婆的方式去访问或操作她时,她未必真正按老婆的方式回应,根据你的对结果的依赖程度及你的操作深度,也许会是系统灾难。

出0入0汤圆

发表于 2010-9-27 17:45:52 | 显示全部楼层
学习!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-22 00:46

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表