独闷闷网

 找回密码
 立即注册
搜索
查看: 3287|回复: 0
打印 上一主题 下一主题
收起左侧

[原创] 不用移位,1个long类型数据和4个的char数据,它们之间如何分解和合并?已解答。

[复制链接]
跳转到指定楼层
楼主
发表于 2016-10-16 09:56:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 jianhong_wu 于 2016-10-18 11:31 编辑

问:
不用移位,1个long类型数据和4个的char数据,它们之间如何分解和合并?

★坚鸿-深圳:
      我们在项目中,数据格式在存储,通讯,显示的过程中,经常要进行切换,比如,一个unsigned long的数经常要“化整为零”成为4个字节的unsigned char数据,一个unsigned int经常要“化整为零”成为2个字节的unsigned char数据。反过来,4个字节的unsigned char要“化零为整”成为一个unsigned long数据,2个字节的unsigned char要“化零为整”成为一个unsigned int数据。我以前用的是最直观的方法,就是左移或右移的语句,今晚要跟大家讲讲我最近开始频繁用的另一种方法,那就是指针来处理,用了指针感觉之后,仿佛是从protel99到AD,再也不想回到从前。比如:

      在串口通讯中,主机要把a,b,c三个数打包在一串数据里发送给从机,a是unsigned char类型,b是unsigned int类型,c是unsigned long类型。把它们放到一个buffer[7]数组里,它们在数组内的排列如下:
AA  BB  BB  CC  CC  CC CC。

         用指针,你可以用这样快速处理:
  1. unsigned  char  buffer[7];
  2. unsigned char a;
  3. unsigned int b;
  4. unsigned long c;

  5. unsigned int *pu16;
  6. unsigned long *pu32;

  7. buffer[0]=a;//1个字节直接处理

  8. pu16=(unsigned int*)&buffer[1];
  9. *pu16=b;  //2个字节,一招解决

  10. pu32=(unsigned long*)&buffer[3];
  11. *pu32=c;  //4个字节,一招解决
复制代码


       上面的代码就是发送方的“化整为零”。接着,再跟大家讲接收方是如何快速“化零为整”。
        接收方:

  1. unsigned  char  buffer[7];
  2. unsigned char a;
  3. unsigned int b;
  4. unsigned long c;

  5. unsigned int *pu16;
  6. unsigned long *pu32;


  7. a=buffer[0] ;//1个字节直接处理

  8. pu16=(unsigned int*)&buffer[1];
  9. b= *pu16;  //2个字节,一招解决

  10. pu32=(unsigned long*)&buffer[3];
  11. c= *pu32 ;  //4个字节,一招解决
复制代码


        上面就是接收方的逆向解析处理,特快特顺而且特别有对称感。

         再也不想回到过去那种移位的原始处理,但是,这招方法,也有一个地方要注意,否则稍不留神就会死得很惨。什么地方呢?而是大小端的问题。普通单片机的C51 编译器是大端,而stm32的MDK编译器是小端。

         假如c是unsigned long类型的数据0x12345678,

         用刚才指针的方法,如果你把它存入到一个buffer[4]数组里,不同的编译器,顺序可能不一样。取决于大小端的问题。

在大端编译器下,它的顺序是:
buffer[0]等于0x12
buffer[1]等于0x34
buffer[2]等于0x56
buffer[3]等于0x78


而在小端编译器下,它的顺序是:
buffer[0]等于0x78
buffer[1]等于0x56
buffer[2]等于0x34
buffer[3]等于0x12

顺序是相反的。


        再回到刚才的主机和从机串口通讯的项目,如果主机与从机都是同类的单片机,那么就无所谓大小端,如果主机与从机不是同类的单片机,你就要看看它们的编译环境是大端还是小端,一定要确保双方一致。否则解析出来的数据是恰好相反的。那么问题来,如何知道一个编译器是大端还是小端?很简单,自己随便写个测试程序看看就知道。


         初学者一看到刚才那几行指针代码,一定会被吓晕。为什么?因为他们被绕进去了,这是因为很多教程的问题。而鸿哥的有独特的思路,愿意今夜在这里分享一下。为什么初学者容易绕进去?因为他们太注重语言的局部细节是由哪些主语谓语形容词构成,缺忽略了语言最重要的是意会神会的直接体验感。语言,它是指针还是变量都不重要,重要的是,它哪里跟哪里起了关联,然后再通过哪个符号来操作什么事?所以,写C语言的程序时候,我们还是要用我们平时生活用的中文思维,就不会被绕进去,而且可快速找到规律。

举一个例子:

unsigned  char  buffer[4];
unsigned long c;
unsigned long *pu32;

pu32=(unsigned long*)&buffer[0];
c= *pu32 ;  

        上述代码,它涉及到以下的信息:
(1)要合并几个字节?(哪个语句决定?)
(2)从第几个字节开始? (哪个语句决定?)
(3)指针pu32通过什么语句跟数组buffer有了关联?pu32就像一根吸管什么时候插到了buffer数组?然后pu32从buffer抽血的时候又以什么样的方式抽取? (分别对应哪个语句?)

         以上述这种思路去观察由一堆符号组成的某门新语言,看的时间长了,哪怕你从来没有学过C语言,也能自个找到这门语言的规律并且像破解甲骨文一样无师自通。

        按照这种思路,上述例子的分析如下:
(1)要合并4个字节。(unsigned long*决定。)
(2)从第0个字节开始。 (&buffer[0]决定。)
(3)指针pu32通过pu32=(unsigned long*)&buffer[0]语句跟数组buffer有了关联。此时,pu32指针像吸管一样插入到了buffer数组。
(4)然后pu32从buffer提取数据,是以c=*pu32的方式从buffer里抽4个字节合并好在一起数据。


乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2024-5-2 22:14 , Processed in 0.159441 second(s), 17 queries .

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