【问题标题】:converting 2 byte hex numbers back to a decimal将 2 字节十六进制数字转换回十进制
【发布时间】:2016-12-18 05:01:27
【问题描述】:
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;

【问题讨论】:

  • 这不是关于编程,而是数字系统之间的转换,即数学/算法。并且“下面的代码”不会生成任何输出。
  • 代码将a转换成4个字节。为什么要进行 2 字节的十六进制到十进制的转换?

标签: c hex endianness


【解决方案1】:

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

#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 变量中的正确位置。

我认为它与小端有关?

字节顺序无关紧要,因为移位操作是在考虑到其架构的主机平台上进行的。

【讨论】:

  • NMDV 然而&amp; 0xFFFFFFFFu 看起来很奇怪,尽管它在功能上是正确的,除了将unsigned 转换为int 可能会调用int 溢出并且初始(int) 没有任何作用。此外,OP 确实要求将“2 字节十六进制数字恢复为十进制”。 IDK,猜你今天有tough crowd
  • @chux 啊哈。这是个玩笑,恐怕我知道被否决了 ;) BTW OP 要求 2 个字节,但代码使用 4 个字节来存储 int。关于溢出我确定是由于数字int a 的来源。我错了吗?
  • 不确定。我会考虑的。 (查看 1 的符号/mag 含义)
  • @chux 没有得到你。使用无符号的 32 位十六进制文字如何在有符号时转移溢出,所以 ub?
  • int 分配一个 32 位无符号值是潜在的 UB,而不是移位部分。
【解决方案2】:

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

要序列化您的号码,您可以通过应用位移(分别为 0、8、16 和 24 位)提取号码的每个字节 (&amp;0xff);例如0xAABBCCDD &gt;&gt; 8 变为0xAABBCC,二进制与运算&amp;0xff 丢弃高字节以保留最低有效字节,在示例中为0xCC

要撤消该操作,您必须将字节和它们放在一起,以相反的方向应用位移。解析i 将使用以下代码:

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

这里没有必要强制转换任何操作数,因为在 C 中使用位运算符意味着整数提升 (ISO/IEC 9899§6.3.1.1),并且您得到的变量类型是 int — 也就是说,假设 @987654330 @ 是一个unsigned 8 位整数类型的数组。

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

【讨论】:

  • “这里没有必要强制转换任何操作数,因为在 C 中使用位运算符意味着整数提升”这正是您应该强制转换操作数的原因。有符号类型的位移很容易引发未定义的行为。例如,如果 buf[5] 碰巧持有大于 0x7F 的值,buf[5] &lt;&lt; 24 总是会调用未定义的行为。
  • @Lundin 位运算符与 输出 的符号无关; 6.5.7 描述了两个位移运算符的行为,并且仅区分第一个操作数的符号。假设unsignedbuf 元素的 8 位类型使其安全(它们不会超过 0xFF,因此 &lt;&lt; 24 移位始终是可表示的,因为假定为 32 位整数) — 我编辑了回答以反映这一点。 &amp;-将结果放在一起也是安全的,因为运算符,根据6.5.10,无论输入数据如何,都只进行按位与。
  • 隐式类型提升。如果操作数是任何有符号的小整数类型,它将以带符号的int 结尾。假设在隐式提升之前是无符号的 8 位类型,如果大到足以将数据左移到提升的有符号类型的符号位,则会得到未定义的行为。如果是int,也是未定义的行为。
【解决方案3】:

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

这意味着你有 16 个 0-f,而不是只有 10 个符号 (0-9) 来说明十进制(以 10 为底)系统中的数字。 其中符号 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 表示给定的十六进制符号。

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

【讨论】:

    猜你喜欢
    • 2015-04-18
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 2017-08-23
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    相关资源
    最近更新 更多