【问题标题】:How do I combine 4 2-bit values into 1 8-bit value?如何将 4 个 2 位值组合成 1 个 8 位值?
【发布时间】:2017-08-10 01:52:49
【问题描述】:

此代码是我用来将 4 个 2 位值(无符号字符,但它们仅保存 0-3 的值)组合成 1 个单个无符号字符值的代码

unsigned char nibble = 0;

nibble = (nibble & 0x03) | (output[i] & 0x03);
nibble = (nibble & 0x0C) | (output[i+1] & 0x03) << 2);
nibble = (nibble & 0x30) | (output[i+2] & 0x03) << 4);
nibble = (nibble & 0xC0) | (output[i+3] & 0x03) << 6);

它会为除 00 00 00 00 之外的所有内容生成不正确的值(它通常会为 2 组不同的 2 位值生成相同的结果)。

我很困惑,因为上面的代码是 this code 的编辑,它可以很好地将 2 个 4 位值组合成 1 个字节,那么为什么我的版本没有将 4 个 2 位值组合成 1 个字节?

char byte;
byte = (byte & 0xF0) | (nibble1 & 0xF); // write low quartet
byte = (byte & 0x0F) | ((nibble2 & 0xF) << 4); // write high quartet

我尝试将 0x03 / 0x0C / 0x30 / 0xC0 更改为 0xC0 / 0x30 / 0x0C / 0x03,仍然错误。将 & 0x03 更改为 & 0xC0 也是如此。

【问题讨论】:

  • 就个人而言,我不会费心做掩码的事情,只需直接添加值。如果您没有进行大量优化的编译器,则代码更大,但速度更快。第一行:nibble |= output[i]; 第二行:nibble &lt;&lt;= 2; 但是它不应该解决你的问题。 (哦,很好,因为问题在于您的 = 运算符。)

标签: c++ c bit-manipulation bit bit-shift


【解决方案1】:

这是因为你每次都清除半字节中的位。

也就是说,当你这样说时:

nibble = (nibble & 0xC0)

你真正的意思是“扔掉我到目前为止所做的所有工作,除了位置 3 和 4 的位”。

此代码(未经测试)可能会解决您的问题:

unsigned char nibble = 0;

nibble |= (output[i  ] & 0x03);
nibble |= (output[i+1] & 0x03) << 2;
nibble |= (output[i+2] & 0x03) << 4;
nibble |= (output[i+3] & 0x03) << 6;

如果 真的output[i+x] 只保存 [0,3] 范围内的值,那么您可以按如下方式更改代码:

unsigned char nibble = 0;

assert(0<=output[i  ] && output[i  ]<=3)
nibble |= output[i  ];
assert(0<=output[i+1] && output[i+1]<=3)
nibble |= output[i+1] << 2;
assert(0<=output[i+2] && output[i+2]<=3)
nibble |= output[i+2] << 4;
assert(0<=output[i+3] && output[i+3]<=3)
nibble |= output[i+3] << 6;

如果您真的,真的确定,当然可以删除断言。但是您也可以保留它们并让编译器使用NDEBUG 标志 (g++ -DNDEBUG mycode.cpp) 来消除它们。详情请见this question

【讨论】:

  • 如果保证了OP的声明(unsigned chars but they only hold values from 0-3),那么&amp; 0x03的4个实例可以省略。
【解决方案2】:

这是因为在使用新位填充 nibble 之前,您使用掩码对其进行过滤,如果有任何与它应该做的相反的事情。

nibble = (nibble & 0x03) | (output[i] & 0x03);
nibble = (nibble & 0x0C) | (output[i+1] & 0x03) << 2);
nibble = (nibble & 0x30) | (output[i+2] & 0x03) << 4);
nibble = (nibble & 0xC0) | (output[i+3] & 0x03) << 6);
                   ^^^^ in here you preserve the bits
             you want to replace and zero out everything else

反转该掩码会起作用:

nibble = (nibble & ~0x03) | (output[i] & 0x03);
nibble = (nibble & ~0x0C) | (output[i+1] & 0x03) << 2);
nibble = (nibble & ~0x30) | (output[i+2] & 0x03) << 4);
nibble = (nibble & ~0xC0) | (output[i+3] & 0x03) << 6);

但是,由于nibble 已经以0 开头,所以您不需要它。只需像Richard's answer 一样填充位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2021-12-20
    相关资源
    最近更新 更多