【问题标题】:Bitwise operator to get byte from 32 bits按位运算符从 32 位获取字节
【发布时间】:2011-09-01 23:53:44
【问题描述】:

我有兴趣编写一个函数getMyByteChunkFunction,它接受两个参数 - 一个 32 位整数和一个字节偏移量(0、1、2 或 3),然后返回 32 位整数中的相应字节.例如,给定这个整数:

            (3)         (2)      (1)      (0)   ---byte numbers
int word = 10101010 00001001 11001010 00000101

函数调用getMeByteChunkFunction(word, 2)返回00001001

但是,我可以使用的位运算符有限。我只能使用>><<正好一个减法。我知道如何使用 AND 和 XOR 来做到这一点,但我不知道如何在这里使用减法。有什么想法吗?

【问题讨论】:

标签: c++ c algorithm bit-manipulation


【解决方案1】:

一个想法如下。假设你有一个像这样的四字节值:

aaaaaaaa bbbbbbbb cccccccc dddddddd

假设您想从中获取字节bbbbbbbb。如果你右移两个字节,你会得到

???????? ???????? aaaaaaaa bbbbbbbb

这个值等于你想要的值,除了它在顶部有???????? ???????? aaaaaaaa(因为我们不确定移位是否保留符号,因为我不知道你的值是否是无符号的与否。)不过,不用担心;我们可以摆脱这些未知值和a 字节。为了摆脱顶部,假设您向右移动另一个字节,给出

???????? ???????? ???????? aaaaaaaa

现在,左移一个字节得到

???????? ???????? aaaaaaaa 00000000

如果你再做这个减法,你会得到

    ???????? ???????? aaaaaaaa bbbbbbbb
-   ???????? ???????? aaaaaaaa 00000000
---------------------------------------
    00000000 00000000 00000000 bbbbbbbb

瞧……你已经得到了你想要的价值!

我将把实际代码留给读者作为练习。不用担心;这不是特别难。 :-)

【讨论】:

  • @Tom Zych- 哎呀!谢谢你抓住那个。我不擅长指路。 :-)
  • @templatetypedef,帖子下的评论错误...我最好休息一会儿。 ;-)。
  • 被提名为具有最多问号的合法 StackOverflow 答案。 (???????? ???????? ????????)
  • 如果您只允许使用 > 和一次减法,您可能需要记住,
【解决方案2】:

你可以通过换档来做到这一点。左移去掉左边的位,然后右移去掉右边的位,把想要的字节移到最不重要的位置。

【讨论】:

  • 如果位移是符号保留,这不会有问题吗?
  • 您可以先将其转换为未签名的吗?那会照顾它的。如果没有,请使用 templatetypedef 的答案。
【解决方案3】:

下面的代码也应该回答这个问题。

#include <stdio.h>

int getByte(int x, int n);

void main()
{
    int x = 0xAABBCCDD;
    int n;

    for (n=0; n<=3; n++) {
        printf("byte %d of 0x%X is 0x%X\n",n,x,getByte(x,n));
    }

}

// extract byte n from word x
// bytes numbered from 0 (LSByte) to 3 (MSByte)
int getByte(int x, int n)
{
    return (x >> (n << 3)) & 0xFF;
}

输出是

byte 0 of 0xAABBCCDD is 0xDD
byte 1 of 0xAABBCCDD is 0xCC
byte 2 of 0xAABBCCDD is 0xBB
byte 3 of 0xAABBCCDD is 0xAA

这个概念可以根据templatetypedef的解释来解释,扩展如下。

(3)      (2)      (1)      (0)
aaaaaaaa bbbbbbbb cccccccc dddddddd

{(3),(2),(1),(0)} --> {(3)}
  ???????? ???????? ???????? aaaaaaaa // x>>(3*8) where 3 == n
& 00000000 00000000 00000000 11111111 // 0xFF
  -----------------------------------
  00000000 00000000 00000000 aaaaaaaa // (x >> (8 * n)) & 0xFF

{(3),(2),(1),(0)} --> {(2)}
  ???????? ???????? aaaaaaaa bbbbbbbb // x>>(2*8) where 2 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 bbbbbbbb

{(3),(2),(1),(0)} --> {(1)}
  ???????? aaaaaaaa bbbbbbbb cccccccc // x>>(1*8) where 1 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 cccccccc

{(3),(2),(1),(0)} --> {(0)}
  aaaaaaaa bbbbbbbb cccccccc dddddddd // x>>(0*8) where 0 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 dddddddd

Note (x >> (8 * n)) & 0xFF is equivalent to (x >> (n << 3)) & 0xFF.

64 32 16 8 4 2 1 
----------------
0  0  0  0 0 1 1 // (n==3)
0  0  1  1 0 0 0 // (n*8==n<<3==24)
----------------
0  0  0  0 0 1 0 // (n==2)
0  0  1  0 0 0 0 // (n*8==n<<3==16)
----------------
0  0  0  0 0 0 1 // (n==1)
0  0  0  1 0 0 0 // (n*8==n<<3==8)
----------------

【讨论】:

    【解决方案4】:
    result = (word >> (n_byte << 3)) & 0xFF;
    

    【讨论】:

    • 右移到 8*n_byte 并用 0xFF 掩码得到字节
    【解决方案5】:

    对此有一个非常聪明的技巧,我用它来将对象转换为 char 字符串(以流形式传输):

    //WhichByte should really be an enum to avoid issues
    //Counts as 0, 1, 2 or 3
    //Modify as unsigned or signed char (for return type and pointer type) as needed
    #define BYTE_TYPE unsigned char
    BYTE_TYPE GetByte(const unsigned int Source, const unsigned char WhichByte)
    {
        if(WhichByte < 0){return 0;}
        if(WhichByte >= sizeof(Source)){return 0;}
    
        //Converts source into the appropriate pointer
        BYTE_TYPE * C_Ptr = (BYTE_TYPE *)&Source;
        return *(C_Ptr+WhichByte);
    }
    #undef BYTE_TYPE
    

    简而言之,上面将 source 视为 4 个单独的字符(通常只有 1 个字节大小),并且指针允许您将其视为内存部分。您在返回之前取消引用它。

    将其用于任何目的(甚至是商业用途)。

    压缩格式?

    #define GetByte(X,Y) (*(((unsigned char *)&X)+Y))
    

    【讨论】:

      【解决方案6】:

      代码如下:

      #include <stdio.h>
      
      int main() {
          unsigned long n = 0xAA09CA05L; /* 10101010 00001001 11001010 00000101 */
          printf("%08lx\n", n); /* input */
          printf("%02lx\n", ((n<<8)>>24)); /* output */
          return 0;
      }
      

      和输出:

      aa09ca05
      09
      

      【讨论】:

      • ANSI/ISO C 规范说 long 必须至少 4 个字节。你知道有哪些兼容 ANSI 的 C 编译器无法运行吗?
      • 这个答案没有解释为什么代码有效 - 你能详细介绍一下吗?如果你想要第二个字节以外的东西怎么办?当输入值为int 时,为什么要使用unsigned long
      • @templatetypedef:大部分这些问题的答案都可以在我的回答中找到;这个答案实现了相同的想法。
      • @Michał Šrajer ISO C 没有指定使用哪种移位,因此您可以轻松获得算术移位。现在可以轻松地使用无符号类型并希望每个编译器都遵循通常的约定,但这并不是最好的答案(尤其是使用无符号值而不提及其重要性)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 2020-08-18
      • 1970-01-01
      • 2010-11-05
      • 2012-09-19
      • 1970-01-01
      相关资源
      最近更新 更多