【问题标题】:Convert hexadecimal made up of 0's and 1's to binary equivalent将由 0 和 1 组成的十六进制转换为等效的二进制
【发布时间】:2018-10-05 08:12:13
【问题描述】:

我需要一个十六进制数转换为另一个表示它的二进制值的数字(虽然不是实际值)。

例如,如果我有 0x0101,我想得到 0b0101,即 0x5。我一开始得到的十六进制总是由 0 和 1 组成。

这也可能是一种将 0xf00f 转换为 0b1001(0xf 转换为 0b1 而不是 0x1 转换为 0b1)的方法,即 0x9。实际上,我开头的十六进制数是由 f 和 0 组成的,但是通过将 f 除以 0xf 很容易将 f 替换为 1。示例:

uint16_t bitMask = 0xf0f0;
uint16_t nybbleMask = 0;

//do some bit manipulation with bitMask
//get nybbleMask == 0xc (0b1010)

或:

bitMask = bitMask / 0xf;
//bitMask is now 0x1010

//do some bit manipulation with bitmask
//get nybbleMask == 0xc (0b1010)

编辑:我知道我可以很容易地用循环来做到这一点,但我想知道我是否可以用按位运算器做一些等效的事情。另外,我无权访问math.h 库。

【问题讨论】:

    标签: c binary hex bit-manipulation


    【解决方案1】:

    这是一个非常简单的问题,我认为这是家庭作业。 @tom 让它变得比它需要的更难。

    您只想从最低有效位开始提取每 4 位,忽略中间的 3 个零。我给你一个算法。编写代码应该不难:

    let x be the hex coded binary number to convert
    let val be the binary result value, initially zero
    let n be the bit position we're currently finding, initially zero
    while x is not zero
      let b be the least significant bit of x
      update val to be val or (b shifted left by n bits)
      increment n
      update x to be x shifted right by 4 bits
    

    这是另一种方法:

    let val be 0
    let hex_mask be 1
    let bin_mask be 1
    while hex_mask is not zero
      if (x and hex_mask) is non-zero, then update val to be val or bin_mask
      shift hex_mask left 4 bits
      shift bin_mask left 1 bit
    

    加法

    既然你说这不是作业,让我告诉你第二个解决方案实际上一个只有位运算符的解决方案,如果你有一个好的编译器。

    代码如下:

    uint16_t hex_coded_binary_value(uint16_t x) {
      uint16_t val = 0;
      for (uint16_t h = 1, b = 1; h; h <<=4, b <<= 1)
        if (x & h) val |= b;
      return val;
    }
    

    如果你用最新版本的 Apple clang 编译它,你会得到:

    mov eax, edi
    and eax, 1
    mov ecx, edi
    shr ecx, 3
    and ecx, 2
    or ecx, eax
    mov eax, edi
    shr eax, 6
    and eax, 4
    or eax, ecx
    shr edi, 9
    and edi, 8
    lea eax, [rdi + rax]
    ret
    

    注意没有循环!这都是移位、和、或、添加和移动。 gcc 使用条件移动指令,但也没有循环。

    编译器发现的算法是什么?如果你用 C 编码,它看起来像:

    val = (x & 1)
        | ((x >> (4 - 1)) & (1 << 1))
        | ((x >> (8 - 2)) & (1 << 2))
        | ((x >> (12 - 3)) & (1 << 3));
    

    这折叠成

    val = (x & 1) | ((x >> 3) & 2) | ((x >> 6) & 4) | ((x >> 9) & 8);
    

    请注意,结果的操作比@tom 的解决方案少。

    这也编译为与原始版本基本相同,但 C 更长且更容易出错。道德是相信你的编译器。

    【讨论】:

    • 这不是家庭作业,但您的算法运行良好。 :) 但是我更多的是寻找一种仅使用按位运算符来执行此操作的方法,循环确实非常简单。我在我的 OP 中澄清了这一点。
    • @JeremyPare 请看补充。通常,试图击败编译器是个坏主意。
    【解决方案2】:

    16 位十六进制的一行修复将是....

    bin = ((hex%16)?1:0) + (((hex/16)%16)?2:0) + (((hex/256)%16)?4:0) + (((hex/4096)%16)?8:0);
    

    虽然这不是您想要的按位运算。不确定&gt;&gt; 是否适用于int 或至少指定为始终适用于uint16_t - 您可能想查看this question 以考虑按位运算符和uint16_t - 如果可以,那么

    bin = (hex & 1) |
          (((hex >> 4) & 0x1) << 1) |
          (((hex >> 8) & 0x1) << 2) |
          (((hex >> 12) & 0x1) << 3);
    

    如果您的 hex 字节是 F0,则可以使用。

    任意大小十六进制的旧答案如下

    int hex;
    int bin;
    
    int n, m, k;
    
    //assume hex has your hex value
    n=0; bin=0;
    while(pow(16.0,(double)n)<(double)hex+0.5) // test if we are done
     {
      m=1; for(k=0;k<n;k++) m*=16; 
      if ((hex/m)%16!=0) {
         m=1;for(k=0;k<n;k++) m*=2;
         bin += m;
      }
      n++;
     }
    

    这应该将任何 0x.... 转换为 0b.... 如果十六进制数字不等于 0,则每个数字都会得到 1。关键部分是(hex/m)%16!=0,它测试hex数字的第n位,看它是零还是非零。

    【讨论】:

    • @JeremyPare - NB 刚刚使用按位解决方案进行了编辑,但我会继续关注它.....很高兴它有帮助
    猜你喜欢
    • 2012-06-26
    • 2012-09-14
    • 2016-08-28
    • 2013-07-25
    相关资源
    最近更新 更多