按位运算符从32位获取字节

Bitwise operator to get byte from 32 bits

本文关键字:获取 字节 32位 运算符      更新时间:2023-10-16

我有兴趣编写一个函数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,但我不知道怎么用减法。什么好主意吗?

思路如下:假设您有一个像这样的四字节值:

aaaaaaaa bbbbbbbb cccccccc dddddddd

让我们假设你想从中得到字节bbbbbbbb。如果右移两个字节,就得到

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

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

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

现在左移一个字节得到

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

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

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

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

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

你可以通过移动来实现。向左移位去掉左边的位,然后向右移位去掉右边的位,并将需要的字节移动到最低有效位

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

#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%Xn",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)
----------------
result = (word >> (n_byte << 3)) & 0xFF;

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

//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))

代码如下:

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

和输出:

aa09ca05
09