2016-12-22 21 views
3

假设你有一个整数a = 0x12345678 &短b = 0xabcd如何与另一组半字节的整数替换给啃

我想要做什么用半字节从short b

更换给出半字节integer a例如:b = 0xabcd(其中d = 0的半字节,c = 0的半字节替换a = 0x12345678(其中8 =第0个半字节,7 =第1个半字节,6 =第2个半字节等等)中的0,2,5,7个半字节)第一级,b =第二级,&等等......)

我的做法是 -

  1. 清除我们打算从a更换位。 像a = 0x02045070
  2. 创建从短b面具像mask = 0xa0b00c0d
  3. 按位OR他们得到的结果。 result = a| maskresult = 0xa2b45c7d因此更换了半字节。

我的问题是我不知道任何高效方式从给定的short b

创建(步骤2等)所需的掩码,如果你能给我一个高效方式这对我很有帮助,我对此表示感谢;)

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

编辑:
我的代码来解决这个问题(还不够好,虽然)
任何改善的高度赞赏。

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; 
+0

result =(a&ffff0000)| b –

+0

@VikashKumarVerma请参阅示例,我想替换**给定的半字节**,您的解决方案将始终替换前四个半字节。 – Mrmj

+1

“给我一种有效的方式” - >在你的平台上,是否使用乘法高效? – chux

回答

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步 - 分配两个NIBBLE项目与您的整数a和短b

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

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

步骤3 - 通过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半字节将是:

a = 12345678 
a = a2b45c7d 
+0

与@sameerkn同样的问题“任何downvote的原因”?建议的答案做请求的工作,并且是人类可读的。 –

-1

随着nibble = 4 bitsunsigned int = 32 bits,内部的一个半字节无符号整数可以发现如下:

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

现在第3个半字节是从12th bit to 15th bit

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

一般情况下,假设如果你想找到的1在二进制表示的连续序列,其中序列从XthYth位,则公式为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 
+0

任何downvote的原因 – sameerkn

0

半位元组具有4个比特,并根据自己的索引方案,第零半字节是由至少显著位在位置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 

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

+0

我见过这个解决方案,但在我的情况下循环是一个很大的不。 – Mrmj

+0

@Mrmj然后展开循环。我的方法非常有效。 – 2501

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 

让我知道如果我误会了,我很高兴能进一步帮助。

+0

感谢大卫的帮助。问题在于'a'中要替换的半字节经常变化。它可以是从1到7的任何半字节,并且可以是任何数目,即1个半字节2个半字节3等等。 – Mrmj

+0

在这种情况下,您可以尝试根据您使用的任何信息来建立自己的面具,以表明它应该是什么。例如,如果你有什么表明它应该是(例如'0,2,6,8'),你可以使用'switch'或'if..then..else if..'来建立你的掩码将'0xf'移到左边,用掩码变量'或'。同时,填写一个'unint8_t'(或结构位域),您可以使用它来确定偏移量以应用于“short”中的字节。它不会是更多的代码,也不需要循环。 –

0

很大程度上取决于你是如何灵活接受你的案例中的“半字节列表”index[4]

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

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

如果您不在具有pdep的平台上,则可以通过乘法完成相同的操作。

相关问题