【问题标题】:how to replace given nibbles with another set of nibbles in an integer如何用整数中的另一组半字节替换给定的半字节
【发布时间】:2017-05-07 17:04:45
【问题描述】:

假设你有一个整数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 创建掩码,如 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;

【问题讨论】:

  • 结果 = ( a & ffff0000 ) | b
  • @VikashKumarVerma 请参阅示例,我想替换 给定的小食,您的解决方案将始终替换前 4 个小食。
  • "给我一个有效的方法" --> 在你的平台上,使用乘法是否有效?
  • 嗯,我认为一个有效的答案是result = (a &amp; a_mask) | ((b*TBD) &amp; b_mask);嗯 - 会思考。
  • 另外:“nibbles list”的格式是什么?它是ints 的数组吗?可以短于4吗?在编译时就知道了吗?

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


【解决方案1】:

半字节有 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

如果要设置多个值,请将此代码放入循环中。变量 index 应该改为值数组,变量 nibble 也可以是值数组,也可以包含多个 nibble,这种情况下通过将值向右移动来逐个提取它们。

【讨论】:

  • 我见过这个解决方案,但在我的情况下循环是一个很大的问题。
  • @Mrmj 然后展开循环。我的方法很有效。
【解决方案2】:

很大程度上取决于您在接受“半字节列表”index[4] 时的灵活性。

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

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

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

【讨论】:

    【解决方案3】:

    为了能够轻松更改半字节分配,可以使用位域联合结构:

    第 1 步 - 创建一个允许 nibbles 访问的联合

    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 步 - 用 b 的半字节初始化 a 的半字节

    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
    

    【讨论】:

    • 与@sameerkn 相同的问题“有什么理由反对”?建议的答案可以完成所要求的工作并且是人类可读的。
    【解决方案4】:

    如果我理解您的目标,那么您的乐趣来自于将您的填充顺序从最终数字的上半部分颠倒到下半部分。 (而不是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
    

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

    【讨论】:

    • 感谢大卫的帮助。问题是a 中要替换的半字节经常更改。它可以是从 1 到 7 的任何半字节以及任何计数,即 1 半字节 2 半字节 3 以此类推。
    • 在这种情况下,您可以尝试根据您用来指示它应该是什么的任何内容来构建您的掩码。例如,如果你有一些东西表明它应该是(例如0, 2, 6, 8),你可以使用switchif..then..else if..通过将0xf向左移动和or'ing来构建你的面具掩码变量。同时,填写一个unint8_t(或结构位域),您可以使用它来确定应用于short 中的字节的偏移量。不会有那么多代码,也不需要循环。
    【解决方案5】:

    使用nibble = 4 bitsunsigned int = 32 bits,可以在无符号整数中找到一个半字节,如下所示:

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

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

    3rd_nibble 可以用n = 2^16 - 2^12 选择。因此,在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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多