如何将 4 个 2 位值合并为 1 个 8 位值?
How do I combine 4 2-bit values into 1 8-bit value?
这段代码是我用来将 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 = (nibble & 0xC0)
你真正想说的是"throw away all the work I've done so far, except for the bits at positions 3 and 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。
那是因为在用新位填充 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
开始,所以您不需要它。只需填充 .
中的位
这段代码是我用来将 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 = (nibble & 0xC0)
你真正想说的是"throw away all the work I've done so far, except for the bits at positions 3 and 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。
那是因为在用新位填充 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
开始,所以您不需要它。只需填充