Sign in to follow this  
vaneger

proper bitwise alterations to an 8 bit char

Recommended Posts

If you want to set the entire byte to a specific bit:
b = 0x1; // bit 0
b = 0x8; // bit 3

If you want to set a paricular bit, use the OR operator, not the && operator.

b |= 0x1; // sets bit 0. retains remainder of byte as-is
b |= 0x4; // sets bit 2

If you want to clear all but a particular bit, use the AND operator:

b &= 1; // clears the entire byte except bit 0. bit 0 stays the same, whether it's a 1 or 0.

b && 0 is not a bit-setting statement. It's a logical TRUE-FALSE statement. It says "result is true if-and-only-if b is true and zero is true." Zero is always false so "b && 0" is always false. Note the difference between "&" and "&&." "&" AND's 2 bits together. "&&" combines true/false variables. Similarly, "|" and "||," for OR'ing bits and OR'ing true/false variables.

In the above cases:
0x1 bit 0
0x2 bit 1
0x4 bit 2
0x8 bit 4
0x10 bit 5
0x20 bit 6
0x40 bit 7
0x80 bit 8

Share this post


Link to post
Share on other sites



you want to use the single & (and) | (or) ^ (xor) bitwise operators


http://www.fredosaurus.com/notes-cpp/expressions/bitops.html



I always use hex values to make it easier to tell which bits values are being used



unsigned char x;

x = 12;

x = x & 0xFE; // turning off a bit

x = x | 0x01; // turning on a bit


I forget if some Cs had a binary literal value ie - 0b00000001 which would make the binary value more obvious.

Share this post


Link to post
Share on other sites
Common operations:

mask = (1 << bitIndex) // create a mask for a single bit (bitIndex starts at 0)

x |= mask // ensures that the particular bit(s) are 1.
x &= ~mask // ensures that the particular bit(s) are 0.
x ^= mask // inverts the specified bit(s)

x &= mask // ensures that all bits NOT part of the mask are 0.
x |= ~mask // ensures that all bits NOT part of the mask are 1.

Share this post


Link to post
Share on other sites
ok so I'm planning on storing indicies into an array of size 1024.That requires 10 bits of data, so I'm wondering if this works:


struct indexBlock
{
unsigned indexA : 10;
unsigned indexB : 10;
unsigned indexC : 10;
unsigned indexD : 10;
};
// 40 bits = 5 bytes for better object construction
// and easier output
indexBlock myIndex;
myIndex.indexA |= 0x01;
myIndex.indexA |= 0x02;
myIndex.indexA |= 0x04;
myIndex.indexA |= 0x08;

myIndex.indexA |= 0x010;
myIndex.indexA |= 0x020;
myIndex.indexA |= 0x040;
myIndex.indexA |= 0x080;

//could I do this instead ?
myIndex.value << 1....10;





How do I set bit 9 and 10 ? ( I don't know hex very well)



[Edited by - vaneger on December 31, 2009 6:46:30 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by vaneger
ok so I'm planning on storing indicies into an array of size 1024.That requires 10 bits of data, so I'm wondering if this works:

*** Source Snippet Removed ***

How do I set bit 9 and 10 ? ( I don't know hex very well)


Well, if you want to write out the hex, you can start by writing out the binary and converting it to hex. Write out the binary digits in sets of four:

Binary: 0000 0010 0000 0000
Decimal: 0 2 0 0
Hex: 0 2 0 0

Final value for code: 0x0200
Setting the bit in the bitmask:

bitmask |= 0x0200.

Alternatively, you could just use bit-shift operators:

bitmask |= (1 << (10 - 1)) //subtract 1 because you're starting from 0, not 1

I'd like to add that its unclear what you're trying to accomplish with your code and description above. Maybe if you wrote out your problem more exactly we could give better advice specifically.

Share this post


Link to post
Share on other sites
the plan is to store indexes into a 1024 element array using only 10 bits as opposed to 16 for a short or 32 for an int. Then for output I want to pack 4 indexes into 5 bytes for output.

Share this post


Link to post
Share on other sites
Quote:
Original post by vaneger
the plan is to store indexes into a 1024 element array using only 10 bits as opposed to 16 for a short or 32 for an int. Then for output I want to pack 4 indexes into 5 bytes for output.


Then you'd want to be able to mask off or set 10 bits at a time, right?

So given an existing index variable and a new index variable, you'd have:

index = (0x02FF & newIndex)

If you want to read that value back out

(0x02FF & index)

When you start packing multiple indexes into a larger variable, then you have to add some extra logical operations and bit-shifting in order to prevent yourself from losing information.

Lets take an unsigned 32-bit integer. You can put 3 of your indexes in their and only waste 2 bits.

So, lets say you want to assign to the middle 10 bits, but leave the upper and lower 10 bits as they are. You have to do three things to accomplish this:

1) Mask out those middle 10 bits
2) Shift your new index so that the bits are in the correct position
3) bitwise or them together

For number 1, you'd want to do something like this:


tempIndex = currIndex & ~(0x02ff << 10);






In this case, you're moving your bitmask and inverting the bits:


0000 0000 0000 0000 0000 0011 1111 1111

to this:

0000 0000 0000 1111 1111 1100 0000 0000

then to this:

1111 1111 1111 0000 0000 0011 1111 1111





When you bitwise-and this with your current index, it will set those middle ten bits to zero.


00XX XXXX XXXX YYYY YYYY YYZZ ZZZZ ZZZZ
1111 1111 1111 0000 0000 0011 1111 1111
---------------------------------------
00XX XXXX XXXX 0000 0000 00ZZ ZZZZ ZZZZ





Where X, Y, and Z are your three stored indexes.

Next, you need to take your new index data and move the bits up to the correct location:


0000 0000 0000 0000 0000 00NN NNNN NNNN

to

0000 0000 0000 NNNN NNNN NN00 0000 0000





(N represents your new index data)

You'd do that with a bitwise operation:


newIndex = (0x02FF & newIndex) << 10;






You'll notice that I'm applying the 10-bit bitmask so that I'm sure that I'm only getting 10-bits worth of data.

Next, you just bitwise-or them together:


currIndex = tempIndex | newIndex;






Which will do the following:



00XX XXXX XXXX 0000 0000 00ZZ ZZZZ ZZZZ
0000 0000 0000 NNNN NNNN NN00 0000 0000
---------------------------------------
00XX XXXX XXXX NNNN NNNN NNZZ ZZZZ ZZZZ






Now your new index data is safely in the correct location.

You can reorganize and consolidate some of these operations into this:


int bitmask = 0x02FF << 10;
int newPackedIndex = (packedIndex & ~bitmask) | (bitmask & (newIndexValue << 10));






Hopefully you can take that information and generalize the solution to what you need.

Share this post


Link to post
Share on other sites
Actually I was thinking on how to pack the 5 bytes last night and I think I'm going to try to take the first 8 bits and put them in the first 4 bytes and then use the last byte for the last 2 bits of each index.

So if I bitshift the index left by 2, will it wrap the last 2 bits around or truncate them ? Also would a bitshift or divide be faster since I'm using 2?

Share this post


Link to post
Share on other sites
Quote:
Original post by vaneger

So if I bitshift the index left by 2, will it wrap the last 2 bits around or truncate them ? Also would a bitshift or divide be faster since I'm using 2?


Unless your compiler is braindead, or 10 or more years old, then it will analyze the values used in mathematical operations, and generate CPU-optimal code. This goes well beyond trivial shift replacement, compilers are capable of many optimizations.


As far as bit tweaking goes, it used to be such popular technique that CPUs today predict many such patterns and execute them differently. Some CPUs however do not do that, leading in very different performance results.


When dealing with arithmetic - first make it right. Then, make sure it is right. After you are absolutely sure, make sure it really correct, even for overflow and similar issues. Then, in the incredibly unlikely case that it is a bottleneck (perhaps you are writing a real-time video encoder for mobile phone) analyze the assembly and study the CPU architecture to try to outperform the compiler.

In short: don't optimize, don't obscure via bitflags, write code as cleanly as possible. And if there really is a need to manipulate bits (file formats, compact encodings), wrap those operations in a sensible interface, either via class or free function.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this