如何用一个整数中的另一组半字节替换给定的半字节

时间:2016-12-22 06:22:27

标签: c bit-manipulation bitwise-operators bit-shift bitmask

假设你有一个整数a = 0x12345678&短b = 0xabcd

我想做的是用integer a中的半字节替换short b中给定的半字节

例如:替换a = 0x12345678中的第0,2,5,7个半字节(其中8 =第0个半字节,7 =第1个半字节,6 =第2个半字节,依此类推......)来自b = 0xabcd的半字节(其中d =第0个半字节,c =第1个半字节,b =第2个半字节&等等......)

我的方法是 -

  1. 清除我们要从a替换的位。 像a = 0x02045070
  2. b
  3. 这样的短mask = 0xa0b00c0d创建模板
  4. 按位OR他们得到结果。 result = a| maskresult = 0xa2b45c7d因此取代了半字节。
  5. 我的问题是我不知道从给定short b <创建所需掩码的任何高效方法(如步骤2中所示) / p>

    如果你能给我一个高效的方式,那对我来说将是一个很大的帮助,我提前感谢你;)

    请询问是否需要更多信息。

    编辑:
    我解决问题的代码(尽管不够好)
    任何改进都受到高度赞赏。

    int index[4] = {0,1,5,7}; // Given nibbles to be replaced in integer
    int s = 0x01024300; // integer mask i.e. cleared nibbles
        int r = 0x0000abcd; // short (converted to int )
         r = ((r & 0x0000000f) << 4*(index[0]-0)) | 
             ((r & 0x000000f0) << 4*(index[1]-1)) | 
             ((r & 0x00000f00) << 4*(index[2]-2)) |
             ((r & 0x0000f000) << 4*(index[3]-3));
        s = s|r;
    

5 个答案:

答案 0 :(得分:1)

很大程度上取决于您在接受“nibble list”index[4]时的灵活性。

您提到可以替换0到8个半字节的任何地方。如果将半字节位作为8位位图而不是列表,则可以将位图用作256条目表中的查找,该表从位图映射到半字节位置为1的(固定)掩码。例如,对于半字节列表{1,3},您将拥有映射到掩码0b00001010的位图0x0000F0F0

然后你可以在x86上使用具有gcc,clang,icc和MSVC内在函数的pdep来将你的短片中的位扩展到正确的位置。例如,对于b == 0xab,您有_pdep_u32(b, mask) == 0x0000a0b0

如果你不在pdep的平台上,你可以通过乘法来完成同样的事情。

答案 1 :(得分:0)

为了能够轻松改变半字节赋值,可以使用位字段联合结构:

第1步 - 创建允许拥有半字节访问权限的联合

typedef union u_nibble {
    uint32_t dwValue;
    uint16_t wValue;
    struct sNibble {
        uint32_t nib0: 4;
        uint32_t nib1: 4;
        uint32_t nib2: 4;
        uint32_t nib3: 4;
        uint32_t nib4: 4;
        uint32_t nib5: 4;
        uint32_t nib6: 4;
        uint32_t nib7: 4;
    } uNibble;
} NIBBLE;

第2步 - 使用您的整数a和短b分配两个NIBBLE项目

NIBBLE myNibbles[2];
uint32_t a = 0x12345678;
uint16_t b = 0xabcd;

myNibbles[0].dwValue = a;
myNibbles[1].wValue = b;

第3步 - 用a的半字节初始化b的半字节

printf("a = %08x\n",myNibbles[0].dwValue);
myNibbles[0].uNibble.nib0 = myNibbles[1].uNibble.nib0;
myNibbles[0].uNibble.nib2 = myNibbles[1].uNibble.nib1;
myNibbles[0].uNibble.nib5 = myNibbles[1].uNibble.nib2;
myNibbles[0].uNibble.nib7 = myNibbles[1].uNibble.nib3;
printf("a = %08x\n",myNibbles[0].dwValue);
  

输出将是:

a = 12345678
a = a2b45c7d

答案 2 :(得分:0)

Nibble有4位,根据你的索引方案,第0个半字节由位置0-3的最低有效位表示,第一个半字节由位置4-7的最低有效位表示,依此类推。

简单地将值移动到必要的数量。这将把半字节设置在由变量索引设置的位置:

size_t index = 5;    //6th nibble is at index 5
size_t shift = 4 * index;    //6th nibble is represented by bits 20-23
unsigned long nibble = 0xC;
unsigned long result = 0x12345678;
result = result & ~( 0xFu << shift );    //clear the 6th nibble
result = result | ( nibble << shift );    //set the 6th nibble

如果要设置多个值,请将此代码放在循环中。变量索引应该更改为值数组,变量半字节也可以是值数组,或者它可以包含多个半字节,在这种情况下,您可以通过向右移动值逐个提取它们。

答案 3 :(得分:0)

如果我了解你的目标,那么你所拥有的乐趣来自于从最后一个数字的上半部分到下半部分的填充顺序的反转。 (而不是0, 2, 4, 6,你想要0, 2, 5, 7)这不是更难,但它确实可以让你计算最终数字中洞的位置。如果我理解了,那么您可以使用0x0f0ff0f0进行掩码,然后使用16, 12, 4 and 0的移位填充零。例如:

#include <stdio.h>

int main (void) {

    unsigned a = 0x12345678, c = 0, mask = 0x0f0ff0f0;
    unsigned short b = 0xabcd;

    /* mask a, fill in the holes with the bits from b */
    c = (a & mask) | (((unsigned)b & 0xf000) << 16);
    c |= (((unsigned)b & 0x0f00) << 12);
    c |= (((unsigned)b & 0x00f0) << 4);
    c |= (unsigned)b & 0x000f;

    printf (" a : 0x%08x\n b : 0x%0hx\n c : 0x%08x\n", a, b, c);

    return 0;
}

示例使用/输出

$ ./bin/bit_swap_nibble
 a : 0x12345678
 b : 0xabcd
 c : 0xa2b45c7d

如果我误解了,请告诉我,我很乐意进一步提供帮助。

答案 4 :(得分:-1)

使用nibble = 4 bitsunsigned int = 32 bits,可以找到unsigned int中的半字节,如下所示:

x = 0x00a0b000,在x中找到第三个半字节,即找到'b'。注意半字节索引以0开头。

现在第三个半字节来自12th bit to 15th bit

可以使用n = 2^16 - 2^12选择3rd_nibble。因此,在n中,第三个半字节中的所有位将为1,其他半字节中的所有位将为0。也就是n=0x00001000

通常,假设您要在二进制表示中找到1的连续序列,其中序列从Xth位开始到Yth位,则公式为2^(Y+1) - 2^X

#include <stdio.h>

#define BUF_SIZE 33

char *int2bin(int a, char *buffer, int buf_size)
{
    int i;
    buffer[BUF_SIZE - 1] = '\0';

    buffer += (buf_size - 1);

    for(i = 31; i >= 0; i--)
    {
            *buffer-- = (a & 1) + '0';
            a >>= 1;
    }

    return buffer;
}


int main()
{
    unsigned int a = 0;
    unsigned int b = 65535;
    unsigned int b_nibble;
    unsigned int b_at_a;
    unsigned int a_nibble_clear;
    char replace_with[8];
    unsigned int ai;
    char buffer[BUF_SIZE];

    memset(replace_with, -1, sizeof(replace_with));
    replace_with[0] = 0; //replace 0th nibble of a with 0th nibble of b
    replace_with[2] = 1; //replace 2nd nibble of a with 1st nibble of b
    replace_with[5] = 2; //replace 5th nibble of a with 2nd nibble of b
    replace_with[7] = 3; //replace 7th nibble of a with 3rd nibble of b

    int2bin(a, buffer, BUF_SIZE - 1);
    printf("a               = %s, %08x\n", buffer, a);
    int2bin(b, buffer, BUF_SIZE - 1);
    printf("b               = %s, %08x\n", buffer, b);

    for(ai = 0; ai < 8; ++ai)
    {
            if(replace_with[ai] != -1)
            {
                    b_nibble = (b & (1LL << ((replace_with[ai] + 1)*4)) - (1LL << (replace_with[ai]*4))) >> (replace_with[ai]*4);
                    b_at_a = b_nibble << (ai * 4);
                    a_nibble_clear = (a & ~(a & (1LL << ((ai + 1) * 4)) - (1LL << (ai * 4))));
                    a = a_nibble_clear | b_at_a;
            }
    }

    int2bin(a, buffer, BUF_SIZE - 1);
    printf("a               = %s, %08x\n", buffer, a);


    return 0;
}


Output:
a               = 00000000000000000000000000000000, 00000000
b               = 00000000000000001111111111111111, 0000ffff
a               = 11110000111100000000111100001111, f0f00f0f