This code is what I am using to combine 4 2-bit values (unsigned chars but they only hold values from 0-3) into 1 single unsigned char value
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);
It produces an incorrect value for everything except 00 00 00 00 (it often produces the same result for 2 different sets of 2-bit values).
I'm confused because the code above is an edit of this code , which works fine to combine 2 4-bit values into 1 byte, so why does my version not combine 4 2-bit values into 1 byte?
char byte;
byte = (byte & 0xF0) | (nibble1 & 0xF); // write low quartet
byte = (byte & 0x0F) | ((nibble2 & 0xF) << 4); // write high quartet
I've tried changing 0x03 / 0x0C / 0x30 / 0xC0 to 0xC0 / 0x30 / 0x0C / 0x03, still wrong. Same for changing & 0x03 to & 0xC0.
It's because you clear bits in the nibble each time.
That is, when you say this:
nibble = (nibble & 0xC0)
what you are really saying is "throw away all the work I've done so far, except for the bits at positions 3 and 4".
This code (untested) will probably solve your problem:
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;
If it's really true that output[i+x]
only holds values in the range [0,3] , then you can change the code as follows:
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;
The asserts could, of course, be removed if you're really, really sure. But you can also leave them in and have the compiler extirpate them by using the NDEBUG
flag ( g++ -DNDEBUG mycode.cpp
). See this question for further details.
That's because before populating nibble
with the new bits you are filtering it with a mask that if anything does the opposite of what it should do.
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
Inverting that mask would work:
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);
However, since nibble
already starts as 0
anyway, you don't need that. Just populate the bits as in Richard's answer .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.