此功能可以将二进制转换为c中的整数吗?



我正在使用此函数将表示为布尔数组的8位二进制数转换为整数。有效吗?我正在嵌入式系统中使用它。它的性能还不错,但我对有些意见或建议(或更换(感兴趣。

uint8_t b2i( bool *bs ){
            uint8_t ret = 0;
            ret  = bs[7] ?   1 : 0;
            ret += bs[6] ?   2 : 0;
            ret += bs[5] ?   4 : 0;
            ret += bs[4] ?   8 : 0;
            ret += bs[3] ?  16 : 0;
            ret += bs[2] ?  32 : 0;
            ret += bs[1] ?  64 : 0;
            ret += bs[0] ? 128 : 0;
            return ret;
        }

如果没有特定的系统,就不可能说。拆卸代码,看看您得到了什么。在特定系统上对您的代码进行基准测试。这是了解手动优化的关键。

通常,有很多考虑因素。CPU的数据单词大小,指令集,编译器优化器性能,分支预测(如果有(,数据缓存(如果有(等

要使代码最佳地执行,无论数据字大小如何,您都可以将uint8_t更改为uint_fast8_t。除非您完全需要8位,否则将其作为uint8_t

缓存使用可能会或可能不会更有效,如果给出了上调整循环。无论如何,循环展开是一种旧的手动优化,我们不应该在现代编程中使用 - 编译器比程序员更有能力进行调用。

代码最糟糕的问题是众多分支。这些可能会导致瓶颈。

您的代码在以下X86机器代码gcc -O2中产生:

b2i:
        cmp     BYTE PTR [rdi+6], 0
        movzx   eax, BYTE PTR [rdi+7]
        je      .L2
        add     eax, 2
.L2:
        cmp     BYTE PTR [rdi+5], 0
        je      .L3
        add     eax, 4
.L3:
        cmp     BYTE PTR [rdi+4], 0
        je      .L4
        add     eax, 8
.L4:
        cmp     BYTE PTR [rdi+3], 0
        je      .L5
        add     eax, 16
.L5:
        cmp     BYTE PTR [rdi+2], 0
        je      .L6
        add     eax, 32
.L6:
        cmp     BYTE PTR [rdi+1], 0
        je      .L7
        add     eax, 64
.L7:
        lea     edx, [rax-128]
        cmp     BYTE PTR [rdi], 0
        cmovne  eax, edx
        ret

许多潜在的潜在效率低下的分支。我们可以通过使用循环使代码更快,更可读:

uint8_t b2i (const bool bs[8])
{
  uint8_t result = 0;
  for(size_t i=0; i<8; i++)
  {
    result |= bs[8-1-i] << i;
  }
  return result;
}

(理想情况下,Bool数组应首先从LSB排列,但这将改变代码的含义与原始代码相比(

提供此计算机代码:

b2i:
        lea     rsi, [rdi-8]
        mov     rax, rdi
        xor     r8d, r8d
.L2:
        movzx   edx, BYTE PTR [rax+7]
        mov     ecx, edi
        sub     ecx, eax
        sub     rax, 1
        sal     edx, cl
        or      r8d, edx
        cmp     rax, rsi
        jne     .L2
        mov     eax, r8d
        ret

更多的说明,但分支更少。它可能会在X86和其他高端CPU上使用分支预测和指令缓存更好地执行您的代码。但是在8位微控制器上比您的代码更糟糕的是,只有指令总数很重要。

您也可以通过循环和位移动来进行此操作以减少代码重复:

int b2i(bool *bs) {
    int ret = 0;
    for (int i = 0; i < 8; i++) {
        ret = ret << 1;
        ret += bs[i];
    }
    return ret;
}

最新更新