将2字节十六进制数转换回小数

时间:2016-08-11 12:38:18

标签: c hex endianness

The code below, produces the following output on a serial console 

[42][25][f][27][0][0]

我的问题是 - 如果只是串口输出 - 你怎么知道这个数字是9999?数学如何运作?我认为这与小端有关吗?

int a = 9999; 
buf[0] = 'B';
buf[1] = '%';
buf[2] = a&0xff;
buf[3] = (a>>8)&0xff;
buf[4] = (a>>16)&0xff;
buf[5] = (a>>24)&0xff;

3 个答案:

答案 0 :(得分:2)

Endianness确定数字在内存中的存储方式,而不是如何对其执行算术运算。由于您提供的C代码仅使用整数运算(即不处理指针和内存访问),因此无论字节顺序如何,结果数据都是相同的。

要序列化您的号码,您可以通过应用位移(分别为0,8,16和24位)来提取数字的每个字节(&0xff);例如0xAABBCCDD >> 8变为0xAABBCC,二进制AND操作&0xff会丢弃高位字节以保留最低有效字节,例如0xCC

要撤消该操作,必须将字节和AND组合在一起,在相反方向上应用位移。解析i将使用以下代码:

int a = buf[2] & (buf[3] << 8) & (buf[4] << 16) & (buf[5] << 24);

这里不需要转换任何操作数,因为在C中使用按位运算符意味着整数提升(ISO / IEC9899§6.3.1.1),并且您得到的变量类型是int - 也就是说,假设buf是一个unsigned 8位整数类型的数组。

请注意,这假设序列化数据的发射器也具有32位int长度,并使用相同的带符号数表示(通常为two's complement)。

答案 1 :(得分:0)

了解数据如何嵌入到消息中,您可以推断它们以正确的格式转换。

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    int32_t a = 9999;
    unsigned char buf[6];
    buf[0] = 'B';
    buf[1] = '%';
    buf[2] = a&0xff;
    buf[3] = (a>>8)&0xff;
    buf[4] = (a>>16)&0xff;
    buf[5] = (a>>24)&0xff;

    uint32_t res= buf[2] + ((buf[3] & 0xFFFFFFFFu) << 8) + ((buf[4] & 0xFFFFFFFFu) << 16) + ((buf[5] & 0xFFFFFFFFu) << 24);

    printf("Converted from chars: %d\n", res);

    return 0;
}

当数据被推入缓冲区时,您可以将它们放回到int变量中的正确位置。

  

我认为它与小端有关?

Endianness并不重要,因为考虑到其架构,在主机平台上进行轮班操作。

答案 2 :(得分:0)

河西十进制数系统是基数为16的数字系统。 这意味着它由16个不同的符号组成,其权重为16.

这意味着不是只有10个符号(0-9)来说明数字,如十进制(基数10)系统,你有16 0-f。   在十进制中符号a = 10,b = 11,c = 12,d = 13,e = 14和f = 15。

系统的权重部分意味着十六进制数字中的第一个符号的权重为1,十进制系统也是如此。   但如果数字由多个数字表示,则该权重增加16。

所以在十六进制中:

  • f = 16 ^ 0 * 15十进制。
  • ff =(16 ^ 1 * 15)+15十进制。

  • fff =(16 ^ 2 * 15)+(16 ^ 1 * 15)+15十进制

  • n ... fff =((16 ^ n-1)* m)+ ... +(16 ^ 2 * 15)+(16 ^ 1 * 15)+15十进制,其中m代表给定的十六进制符号

这个数字系统广泛用于电子工程和软件开发附近的硬件,因为它允许用四组分组,从而说明更大的二进制数。