连接n个字节的第7个低位

时间:2014-09-19 13:55:24

标签: c++ c bit-manipulation

我只是想知道这两个表达式之间是否有任何区别:

1:a = ( a | ( b&0x7F ) >> 7 );

2:a = ( ( a << 8 ) | ( b&0x7F ) << 1 );

我不仅谈论结果,还谈论效率(但第一个看起来更好)。

目的是连接多个字节的7个低位,我最初使用的是数字2,如下所示:

while(thereIsByte)
{
  a = ( ( a << 8 ) | ( b&0x7F ) << i );
  ++i;
}

感谢。

2 个答案:

答案 0 :(得分:4)

这两个表达式没有任何相似之处:

  1. a = ( a | ( b&0x7F ) >> 7 );
  2. <强>解释

    a              = 0010001000100011
    b              = 1000100010001100
    0x7f           = 0000000001111111
    b&0x7f         = 0000000000001100
    (b&0x7f) >> 7  = 0000000000000000 (this is always 0), you are selecting the lowest 
                                       7 bits of 'b' and shifting right 7bit, discarding
                                       the selected bits).
    (a | (b&0x7f) >> 7) always is equal to `a`
    
    1. a = ( ( a << 8 ) | ( b&0x7F ) << 1 );
    2. <强>解释

      a              = 0010001000100011
      b              = 1000100010001100
      0x7f           = 0000000001111111
      b&0x7f         = 0000000000001100
      (b&0x7f) << 1  = 0000000000011000
      (a << 8)       = 0010001100000000
      (a << 8) | (b&0x7F) << 1 = 0010001100011000
      

      在第二个表达式中,结果将具有a的3个最低字节作为3个最高字节,而b的最低字节没有最高位,向左移位1位。行a = a * 256 + (b & 0x7f) * 2

      如果要连接ba的最低7位,则为:

      while (thereIsByte) {
          a = (a << 7) | (b & 0x7f);
          // read the next byte into `b`
      }
      

      例如,在sizeof(a) = 4个字节的情况下,并且您连接了4个7位信息,伪代码的结果将是:

      a = uuuuzzzzzzzyyyyyyyxxxxxxxwwwwwww
      

      z是第一个字节的7位,y是第二个字节的7位,依此类推。 u是未使用的位(包含开头a最低4位的信息)

      在这种情况下,a的大小需要大于要连接的总位数(例如:如果要连接四个7位信息,则至少为32位)。

      如果ab是一个字节大小不会真正连接,你可能需要一个像boost::dynamic_bitset这样的数据结构,在那里你可以多次追加位并且它会增长accondinly。

答案 1 :(得分:1)

是的,他们是不同的。在MSVC2010上,当a和b都是字符时,这里是反汇编。

a = ( a | ( b&0x7F ) >> 7 );
012713A6  movsx       eax,byte ptr [a]  
012713AA  movsx       ecx,byte ptr [b]  
012713AE  and         ecx,7Fh  
012713B1  sar         ecx,7  
012713B4  or          eax,ecx  
012713B6  mov         byte ptr [a],al  

a = ( ( a << 8 ) | ( b&0x7F ) << 1 );
012813A6  movsx       eax,byte ptr [a]  
012813AA  shl         eax,8  
012813AD  movsx       ecx,byte ptr [b]  
012813B1  and         ecx,7Fh  
012813B4  shl         ecx,1  
012813B6  or          eax,ecx  
012813B8  mov         byte ptr [a],al  

请注意,第二种方法执行两次移位操作(总共9个移位位,每个位移一个时钟周期),而第一种方法执行单次移位(仅7位)并读取。基本上这是由操作顺序引起的。第一种方法更加优化,但是移位是计算机最有效的操作之一,对于大多数应用来说,这种差异可能是微不足道的。

请注意,编译器将它们视为字节,而不是签名的整数。