首页 > 其他分享 >一些关于字节序处理的一些经验

一些关于字节序处理的一些经验

时间:2022-11-09 13:24:32浏览次数:42  
标签:00 经验 字节 mantissa 0x00 0x43 一些 local

特别是接触下位机 或者socket数据流处理,总少不了涉及所谓字节序问题。今天又拿这个出来说事了。有点啰嗦哈

偶然翻到微量氧项目的ModbusRTU 寄存器说明 ,有这么一段说明:
从站地址默认为0x01
字节序:每个寄存器均一个2字节数据 ,下位机发时遵循 先发高位 再发低位。
比如下位机发 0xff00 那么上位机收到的 byte[] readDatas; 为 readDatas={0xff,0x00}
想着先发高位对方收到的ff 00 对的哈 ,仔细一想 我擦 越想越不对 ,在未发送前 0xff00 按照little字节序 ff可是高位噢。对应65280, 你一发送后 变成了{ff,00} 低字节对应低位 别人用little字节序一转换变成 255了 这不扯淡么。但是 但是 但是 这不是我自己写的么 ,当时我就怎么写出这段话来的呢,鬼使神差?不得不说这玩意儿确实个绕 绞人的东西 ,现在这社会 人浮躁的甚至到了都不能静下心来认真理解一段话的程度了。为了刨根问底儿追这些细节我们来调测一下:

首先是字节序说明和测试:

little字节序,即小端字节序 高字节数据在地址或者数组的高位 ,低字节数据在地址或者数组的低位。这也是符合我们正常人思维理解概念的一种字节序 ,且也是大多数编程环境支持的一种默认处理方式。
另一种与之相反是big字节序 我们这里不做说明。


c#中默认是intel架构 的little字节序 所有的字节数据处理也是遵循的。好的我们 首先编写一段简单的不能再简单的代码

1 UInt16 testNum = 0xff00;//65280
2 byte[] btstest = BitConverter.GetBytes(testNum);
3 
4 //byte[] btstest2 = { 0xff, 0x00 };
5 UInt16 testNum2 = BitConverter.ToUInt16(btstest, 0);
6 Console.WriteLine(testNum2.ToString());

都知道"hello" 数组末尾以\0结尾 数组的高索引代表高位 ,那么上面应该是{00,ff}这种看似简单的东西容易把人绞昏。为什么推进little字节序。你想想这边的环境 发送到对方那 对方也接收到一个数组里 ,先发低地址也就是ff  对方越收到越往数组的后面 排    {ff,00}->{ff,00}  这边环境的东西跟对方环境的东西完全一样,这样才符合人惯性思维的预期 是不是这样。

那我们看下到底是不是高位就在高地址

 

 

 嗯 确实是的对吧。输出65280完全没问题。

 

另外一种处理方式的来由

但是看到下面一段代码 ,反向了?

 1 float oxMeasure = float.Parse(textBox1.Text);
 2 //0,0,127,67
 3 //0x43 7f 00 00
 4 //{0x00,0x00 ,0x7f,0x43}
 5 byte[] oxmeasureData = BitConverter.GetBytes(oxMeasure);
 6 
 7 byte[] uploadData = { 0xEE, 0xB5, 0x02, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFC, 0xFF, 0xFF };
 8 //高低位反向
 9 uploadData[5] = oxmeasureData[3];
10 uploadData[6] = oxmeasureData[2];
11 uploadData[7] = oxmeasureData[1];
12 uploadData[8] = oxmeasureData[0];
13 //ComDevice.Write(uploadData, 0, uploadData.Length);

如上代码所描述 反向了,先发高位,那么下位机收到的应该是{0x43,0x7f,0x00,0x00}

为什么要这样写呢。

我们代码这里应该是oxmeasureData = {0x00,0x00 ,0x7f,0x43} ,反着发下位机收到 {0x43,0x7f,0x00,0x00 } ,下位机每收到一个字节都加到字符串然后输出调试。

 1 function measureProcess(parid, parData)
 2     local measureHexStr = "";
 3     local measureval = 0.0;
 4     for i = 1, #parData, 1 do
 5         measureHexStr = measureHexStr .. string.format('%02X', parData[i]);
 6     end
 7     --print(measureHexStr.."------");
 8     measureval = hexToFloat(measureHexStr);
 9     if parid == 1 then --通道1
10         globalvar_ch1_measure = measureval;
11     elseif parid == 2 then --通道2
12         globalvar_ch2_measure = measureval;
13     elseif parid == 3 then
14         globalvar_ch3_measure = measureval;
15     elseif parid == 4 then
16         globalvar_ch4_measure = measureval;
17     end
18     
19 end

 

 

 

那么 问题来了,看到输出的字符串没有 ,转过来了,学过c语言都知道, 0x43是字符串数组中的低位,但是这里是当作全字符串来处理的 就像我们平常书写代码一样//"0x43 7f 00 00",却恰巧可以正确转换,也正是由于这点小小的猫腻 经常导致我们的混乱。

另外晒一下网上抄的一段支持标志ANSI c 也就是所谓,IEEE754的 转换代码 也即标准的c语言float在内存中怎么形式存在的 就怎么形式转换。

 1 function hexToFloat( hexString )
 2     if hexString == nil then
 3         return 0
 4     end
 5     local t = type( hexString )
 6     if t == "string" then
 7         hexString = tonumber(hexString , 16)
 8     end
 9  
10     local hexNums = hexString
11  
12     local sign = math.modf(hexNums/(2^31))
13  
14     local exponent = hexNums % (2^31)
15     exponent = math.modf(exponent/(2^23)) -127
16  
17     local mantissa = hexNums % (2^23)
18  
19     for i=1,23 do
20         mantissa = mantissa / 2
21     end
22     mantissa = 1+mantissa
23 --    print(mantissa)
24     local result = (-1)^sign * mantissa * 2^exponent
25     --保留一位小数
26     result = math.floor(result * 10+ 0.5) / 10;
27     return result
28 end

事情往就是在这样绞来绞去的过程中 不知不觉就被带偏了 ,然后就囫囵吞枣的过。

 

标签:00,经验,字节,mantissa,0x00,0x43,一些,local
From: https://www.cnblogs.com/assassinx/p/16873274.html

相关文章

  • 关于AP的一些知识点
     FAT模式是指AP可以独立配置,有独立的管理接口,就像普通的无线AP一样;胖模式主要用于不使用交流电的小型网络。FIT模式是指AP由TP-LINKAC(无线控制器)统一控制和设置。 ......
  • java--IO流☛☛字节缓冲流✪
    字节缓冲流字节缓冲流介绍BufferedOutputStream(OutputStreamout):该类实现缓冲输出流.通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每......
  • 关于Docker的一些事--Docker部署以及常用的命令
    Docker部署 docker的基本构成   可能图片有点模糊。。。从左到右:客户端、docker主机、远程仓库镜像 imagedocker镜像就好比是一个模板,可以通过这个模板来......
  • 关于Docker的一些事--Docker概述
    为什么会出现docker?背景以一个食品工厂为例子,有一款食品产品,从研发到包装,需要分别两套生产线,虽然感觉说很好,符合SOP,但是吧,产能很慢,这是为什么呢?研发:食品搭配、颜色搭配......
  • java--IO流 ☞ 字节流
    IO流概述和分类IO流介绍IO:输入/输出(Input/Output)流:是一种抽象概念,是对数据传输的总称,流的本质是数据传输IO流就是用来处理设备间数据传输问题的。常见的应......
  • 关于 i=i++ 的字节码原理
    在学jvm之前,我也认为i++与++i的区别就是一个先使用i的值,再自增;一个先自增,再使用i的值。直到我遇到了i=i++。 inti=10;i=i++;System.out.println......
  • for和while的一些很基础的知识点 1.0版
    今天的​啊意也是忙碌的大学牲,匆匆忙忙只学了for和while很基础的一些知识点,下面便让我总结下我今天学到的东西吧下图是for执行的顺序首先就是for循环,for的基础结构就是:for......
  • 对接第三方项目遇到的一些问题
    目前开发的项目中,根据实际需求要和其他项目进行对接,来实现一些功能。最开始对接的就是获取菜单资源信息。菜单相关信息全部是配置在其他项目中的,需要使用的时候就直接......
  • 一些有用的sql
    删除重复行,按照某列DELETEs1FROMfilter_md5ASs1INNERJOINfilter_md5ASs2WHEREs1.fm_id<s2.fm_idANDs1.md5=s2.md5;给一个表添加unique......
  • 数据库项目实战中的一些细节
    在结构体中,都用字符串表示,因为整数,浮点数不能表示为NULL;在表中,浮点数据都用int类型表示,例如:1.25元,在数据库中,应表示为125分。/project/idc1/c/obtmindtodb2.cpp......