Given an array,
unsigned char q[32]="1100111..."
,
how can I generate a 4-bytes bit-set, unsigned char p[4]
, such that, the bit of this bit-set, equals to value inside the array, e.g., the first byte p[0]= "q[0] ... q[7]"; 2nd byte p[1]="q[8] ... q[15]", etc.
and also how to do it in opposite, i.e., given bit-set, generate the array?
my own trial out for the first part.
unsigned char p[4]={0};
for (int j=0; j<N; j++)
{
if (q[j] == '1')
{
p [j / 8] |= 1 << (7-(j % 8));
}
}
Is the above right? any conditions to check? Is there any better way?
EDIT - 1
I wonder if above is efficient way? As the array size could be upto 4096 or even more.
According to your example it does not look like you are going for readability, and after a (late) refresh my solution looks very similar to Chriszuma except for the lack of parenthesis due to order of operations and the addition of the !! to enforce a 0 or 1.
I don't think that will quite work. You are comparing each "bit" to
1
when it should really be'1'
. You can also make it a bit more efficient by getting rid of theif
:Going in reverse is pretty simple too. Just mask for each "bit" that you set earlier.
You'll notice the creative use of
(boolean) + '0'
to convert between 1/0 and '1'/'0'.If you are looking for extreme efficiency, try to use the following techniques:
Replace
if
by subtraction of'0'
(seems like you can assume your input symbols can be only0
or1
). Also process the input from lower indices to higher ones.Replace array indices by auto-incrementing pointers:
Unroll the inner loop:
Process several input characters simultaneously (using bit twiddling hacks or MMX instructions) - this has great speedup potential!
First, Use
strtoul
to get a 32-bit value. Then convert the byte order to big-endian withhtonl
. Finally, store the result in your array:There are other ways as well.
But I lack
<arpa/inet.h>
!Then you need to know what byte order your platform is. If it's big endian, then
htonl
does nothing and can be omitted. If it's little-endian, thenhtonl
is just:If you're lucky, your optimizer might see what you're doing and make it into efficient code. If not, well, at least it's all implementable in registers and O(log N).
If you don't know what byte order your platform is, then you need to detect it:
Maybe
long
is 8 bytes!Well, the OP implied 4-byte inputs with their array size, but 8-byte
long
is doable:For
char
that isn't 8 bits (DSPs like to do this), you're on your own. (This is why it was a Big Deal when the SHARC series of DSPs had 8-bit bytes; it made it a LOT easier to port existing code because, face it, C does a horrible job of portability support.)What about arbitrary length buffers? No funny pointer typecasts, please.
The main thing that can be improved with the OP's version is to rethink the loop's internals. Instead of thinking of the output bytes as a fixed data register, think of it as a shift register, where each successive bit is shifted into the right (LSB) end. This will save you from all those divisions and mods (which, hopefully, are optimized away to bit shifts).
For sanity, I'm ditching
unsigned char
foruint8_t
.It's your responsibility to make sure
inChars
is null-terminated. The function will return on the first non-'0'
or'1'
character it sees or if it runs out of output buffer. Some example usage:This just reads 4 bytes, and traps the error if it can't.
This just converts what it can and sets the rest to 0 bits.
This function could be done better if C had the ability to
break
out of more than one level of loop orswitch
; as it stands, I'd have to add a flag value to get the same effect, which is clutter, or I'd have to add agoto
, which I simply refuse.