Skip to main content
GameDev.net gamedev.net
🔒 Locked

bit copy

Started by Doggan Aug 29, 2007 at 12:56 PM 9 replies 5k views
Original Post
Doggan
Doggan
I haven't really programmed for a year. My skills are a bit rusty... How would I copy bit-by-bit in C/C++? memcpy requires a size in bytes, so it cannot work. For example, say I have a 32-bit int, and a byte buffer. int dataArray[10]; char *buffer = new char[8]; I want to copy the least significant 7 bits of each entry in dataArray, and stuff them into buffer contiguously (i.e. no spaces. They should be aligned). How would I do this? I can see a way to do it with STL bitset, but avoiding STL would be nice. Thanks.
clb
clb
I'm afraid you need to work directly with bitwise operations

http://en.wikipedia.org/wiki/Bitwise_operation

Create an appropriate mask for the desired bits to clear the unnecessary bits when assigning to the destination. Use shifts to align the bits as needed. A little pen&paper work to find the proper shift and mask values may be necessary.
Antheus
Antheus
Quote:
How would I copy bit-by-bit in C/C++? memcpy requires a size in bytes, so it cannot work


That is a consequence of common hardware using 8 bits as smallest addressable unit, and being unable to represent per-bit data types.

Whatever method you choose, it'll be your own, but in hardware you'll still need to constrain it to 8-bit boundary.
a2ps
a2ps
well just set each byte in buffer to 0 and xor them with each entry of dataArray.
i THINK that since each entry in buffer is only 1 byte long, it will xor only 8 bits.

for( int i = 0; i < 8; i++ ){buffer = 0;buffer ^= dataArray;}


correct me if its wrong pls, havent tested it so dont know if it works.
EDIT: oh, didnt see you only want the least significant bits of each dataArray entry, and you want no "white" spaces in the buffer, that way you will need shifts to align the bits, like clb said try it on on paper first.
yet, another stupid signature..
Doggan
Doggan
Thanks for the replies.

Quote:
Original post by clb
Create an appropriate mask for the desired bits to clear the unnecessary bits when assigning to the destination. Use shifts to align the bits as needed. A little pen&paper work to find the proper shift and mask values may be necessary.


I understand the bit shifting/masking already. The problem is what I highlighted in bold: how to actually assign to the destination? The source bits are easy to get, but how to get a pointer to the destination at an arbitrary bit to start writing?

Quote:
Original post by a2ps
well just set each byte in buffer to 0 and xor them with each entry of dataArray.
i THINK that since each entry in buffer is only 1 byte long, it will xor only 8 bits.

for( int i = 0; i < 8; i++ ){buffer = 0;buffer ^= dataArray;}


correct me if its wrong pls, havent tested it so dont know if it works.


This will not align the copied bits. Each entry of buffer is 8 bits, and only 7 are being copied. The final bit of buffer will always be invalid. I need to make use of that 8th bit, by copying the first bit of the next dataArray into it.
haegarr
haegarr
BTW: 10 times 7 bits from dataArray makes a total of 70 bits; the buffer provides space for 64 bits (8 times 8 bits). So, err, don't do it!

In general, simulate a bit address by using an integer variable. Clear the buffer. Iterate over the entries in dataArray, increase the bit address integer by 7 for each step, compute the byte (or char) index, the shift offset and the bit mask from it, apply it to the value from the dataArray, and "or" it into the buffer. Notice that this may need to be followed by a second step, since the 7 bits usually will overflow the 8 bits of a char when being shifted.
Evil Steve
Evil Steve
Are dataArray and buffer always those sizes? If so, I'd go for something simple like:
int dataArray[10];char *buffer = new char[8];buffer[0] = (dataArray[0]&0x7f) | ((dataArray[1]&0x40)<<7);buffer[1] = (dataArray[1]&0x3f) | ((dataArray[2]&0x60)<<6);// Etc

Conner McCloud
Conner McCloud
Quote:
Original post by Doggan
I understand the bit shifting/masking already. The problem is what I highlighted in bold: how to actually assign to the destination? The source bits are easy to get, but how to get a pointer to the destination at an arbitrary bit to start writing?

Draw it out on paper. Which bits go where, what masks do you need, et cetera. There should be a nice pattern to it once everything is laid out.

CM
clb
clb
I was trying to write it quite general, because I didn't really understand exactly what you meant. You're talking about stuffing data contiguously, but also with alignment. What kind of alignment? What kind of contiguity?

I'll suppose we're packing the 7 lowest bits of source to a destination, aligning the data so that each byte has 7 actual bits and the highest bit is 0.

That would give something like this:

u32 src[N]; // the 7 LSB bits from each index are desired.
u8 dest[N];

for(int i = 0; i < N; ++i)
dest = src & 0x7F; // 0x7F = 0111 1111b

if you want the bits to be packed as tight as possible, i.e. also using the highest bit of the byte, that would require a little more arithmetic, where you AND, SHIFT and OR the appropriate bits into their place.

The reason for this all is, that you cannot assign only to certain bits with C++. (ok well, with bitfield structs you can). The closest you can get is to

1) write all bits (using =) or
2) use binary AND and OR to set and clear bits.

But there is no explicit "assign the bits 2-9 of this variable to bit pattern (1,0,1,1,1,0,0,1). You could create that kind of helper function by yourself.
Zahlman
Zahlman
Quote:
Original post by Doggan
I want to copy the least significant 7 bits of each entry in dataArray, and stuff them into buffer contiguously (i.e. no spaces. They should be aligned).


Why?

Quote:
I can see a way to do it with STL bitset, but avoiding STL would be nice.


Again, why?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.