?
Solved

checking bit status

Posted on 2003-03-06
26
Medium Priority
?
1,028 Views
Last Modified: 2011-10-03
I need a function to check the status of a bit in an byte or in an array of bytes. For example: isBitSet(mask, bitNum) where mask could be a byte or an array of bytes. Does such of function exists in c++?
0
Comment
Question by:el_rooky
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 7
  • 3
  • +1
26 Comments
 
LVL 6

Expert Comment

by:gj62
ID: 8082929
If you are checking just a single bit, you can use the & operator...

(bitmask & byteToCheck) will return non-zero of the bit set in bitmask is also set in byteToCheck...
0
 
LVL 6

Expert Comment

by:gj62
ID: 8082944
By the way

& operator is referred to as bitwise-AND
0
 

Author Comment

by:el_rooky
ID: 8083097
I am get an error '&' : illegal, left operand has type 'unsigned char [7]'

BYTE bitmask[7];
int byteToCheck;

if (bitmask & byteToCheck) { do something }

Like I said in my question, bitmask could be defined as a single byte or array of bytes.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 6

Expert Comment

by:gj62
ID: 8083343
OK, a few question then....

You have byteToCheck declared as an int - are you checking a byte - or a bit?  If byteToCheck = 18, does that mean check the 18th bit?

Are you checking 1 bit, or a number of bits?

In other words, do you just want to see if the 12th bit is set, or would you want to check if bits 12, 18 and 82 are set?

The answer is, no, there is not a predefined function for you, but it really is not that hard...

I will assume that you want to check the status of 1 bit in any number of bytes...

First, find which bit in the byte to check (assumes that the first position is 0, not 1 and is from the most significant)

bitToCheck = byteToCheck % 8; - gives you which bit you want to check (you need to generate the mask for each one, but that's straightforward

Then find which element in the array you need to check...
arrayOffset = (byteToCheck / 8); - gives you the array subscript to use to get to the byte you need to check

Gotta run, I will follow up later if you need specific code...


0
 
LVL 6

Expert Comment

by:gj62
ID: 8083485
OK, here's some code for you...

int isBitSet(unsigned char *mask, int bitNum)
{
   int bitToCheck = bitNum % 8;
   int byteToCheck = bitNum / 8;
   unsigned char bitmask = 0x80;

   bitmask = bitmask >> bitToCheck;

   if (mask[byteToCheck] & bitToCheck)
      return(1);

   return(0);

}

/* create a 7-byte array and set the 31st bit in the array, then check to see if it is set */

int main()
{
  unsigned char byteArray[7]={0x00,0x00,0x00,0x01,0x00,0x00,0x00};
  int bitCheck = 31;

  if (isBitSet(byteArray,bitCheck))
    printf("The %d bit is set in the array\n", bitCheck);

}
0
 

Author Comment

by:el_rooky
ID: 8083555
I want to check the status of one bit in any number of bytes. Here is my function so far:

bool bit_set(void* bitmask, int bitnum ){
 BYTE ix = bitnum >> 3;
 int x = 1 << bitnum;
 if( ( bitmask[ix] & x ) == x )
           return true;
 return false;
} // BIT SET

Now I need to work on my syntax. I get the following
error C2296: '&' : illegal, left operand has type 'void'
0
 

Author Comment

by:el_rooky
ID: 8083565
gj62,
I've posted my last comment before getting you code. I will check your code now...
0
 

Author Comment

by:el_rooky
ID: 8083612
gj62,
I've posted my last comment before getting you code. I will check your code now...
0
 

Expert Comment

by:ul90
ID: 8083781

bool bit_set(void* bitmask, int bitnum)
{
 return (((unsigned char*)bitmask)[bitnum >> 3] & (1 << (bitnum & 7)))!=0;
}
0
 
LVL 6

Expert Comment

by:gj62
ID: 8083932
UL90,

are you sure you don't want:

bool bit_set(void* bitmask, int bitnum)
{
return (((unsigned char*)bitmask)[bitnum >> 3] & (1 << (7-(bitnum & 7))))!=0;
}
0
 

Author Comment

by:el_rooky
ID: 8083976
gj62,
something is not correct in your code. why are you setting bitmask = bitmask >> bitToCheck;
bitmask is used in your code.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084013
Sorry, typo, the compare should be

     if (mask[byteToCheck] & bitmask)

and not

     if (mask[byteToCheck] & bitToCheck)

Sorry 'bout that...
0
 

Expert Comment

by:ul90
ID: 8084072
gj62,

1 << (bitnum & 7) is correct.

If you want to check if the first bit is set:
 bitnum = 0
-> byte number is (bitnum >> 3) = 0
-> bitmask is (1 << (bitnum & 7)) = 1

With your code, the 8th bit is checked (1 << (7 - (bitnum & 7)) = 0x80).
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084126
ul90,

Your statement is true, but it is incorrect for the problem presented, unless he's using a very odd method of generating the bit number...

If you have an array of 7 bytes, and you want to check the 31st bit, I presumed (as I stated) that the bits are numbered simply from left to right.  

If not you have this wierd situation where the bits are not in numerical sequence e.g.

7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 etc...


Usually, if you are masking off bits in an array, you use left to right referencing, not normal least-signficant to most-signficant.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084154
The bit numbering didn't come out as well as I'd hoped, see "graphic" below <grin>

|    byte 1      |      byte 2           |
|7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 | etc...

Anyhow, I don't think that in the 2-byte array shown above, that you'd actually use 14 to get to the 10th-bit...

Perhaps we should talk about bit-offsets when dealing with arrays.

Anyhow, I think this is what el_rooky is going for, but I am sure he'll correct us if not...
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084160
Drat - that looks worse - anyhow, I think you know what I'm getting at...
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084171
el_rooky - the two routines basically do the same thing...  As I stated, I presumed you were simply numbering the its left to right in the array, and not using least-signficant to most-signficant ordering, for the reason I tried to picture above...

In case you are wondering, the commented portions of each are:

int isBitSet(unsigned char *mask, int bitNum)
{
  int bitToCheck = bitNum % 8;  // this gets the bit position to check within an 8-bit quantity.  It assumes that the bits are numbered from left to right, 0 through 7

  int byteToCheck = bitNum / 8; // this gets the correct byte to check, and also assumes a 0-indexed array, which is great, cuz that is how C is...
 
  unsigned char bitmask = 0x80; // this sets the most significant bit - we'll shift it to the right by bitToCheck (if bitToCheck is 0, we test the most significant bit...) in the next statement:

  bitmask = bitmask >> bitToCheck; //see previous statement

  if (mask[byteToCheck] & bitmask) // a bitwise-AND operation will be non-zero if the bit is set - the returns simply make it explicit... i.e., you could write it as:

return((mask[byteToCheck] & bitmask)!=0);

In ul90's, we'll break the single statement down...

return (((unsigned char*)bitmask)[bitnum >> 3] & (1 << (7-(bitnum & 7))))!=0;

(unsigned char*)bitmask)[bitnum >> 3] - this portion accesses the array by shifting bitnum by 3 bits (integer divide by 8)

(1 << (7-(bitnum & 7))) - this portion accesses the correct bit.  It starts with the least significant bit set, and shifts it to the left by (7-(bitnum & 7)).  (bitnum & 7) masks off the highest 5 bits.  You have to subtract it from 7 assuming that the bit ordering is continuous from left to right in the array (the "bit-offset", if you will...)


0
 

Author Comment

by:el_rooky
ID: 8084349
I am using data generated with a pascal program. I am not sure how the bit numbers are generated. Anyways, I will do some more testing. I am a little bit confused now. Something very strange thought, the following works at least for the first byte:

return (((unsigned char*)bitmask)[bitnum >> 3] & (1 << (6-(bitnum & 7))))!=0;

Note: subtracting 6 and not 7!

I will do some more testing...
0
 
LVL 6

Expert Comment

by:gj62
ID: 8084438
That really should not work.  Remeber that the "bit-offsets" begin at 0, not 1...

Can you post a sample of the byte array (use hex, or the decimal values for each byte) and which bits you think are set?

For example, if you have the byte array:

unsigned char byteArray[7]= {0x81,0x00,0x00,0x00,0x00,0x00,0x00};

if you test for a bitmask of 0x80 (high order bit) or 0x01 (low order bit) both are set, and both return (1)...

0
 
LVL 6

Accepted Solution

by:
gj62 earned 1200 total points
ID: 8084805
Here's a complete test program I wrote - both my method, and the change that I made to ul90's code - appear to work given the assumption of bit-offsets increasing left to right and beginning at 0...

/*

  This code assumes that your are testing for a specific "bit-offset" within an array
  of bytes (unsigned chars).  That is, the bit numbering increases in order from 0 to n,
  starting at the left-most bit in the array...

  There are two different implementations of the same, use whichever you prefer...

  */

#include <stdio.h> /* needed just for printf */

int isBitSet(unsigned char *mask, int bitNum)
{
     int bitToCheck = bitNum % 8;
     int byteToCheck = bitNum / 8;
    unsigned char bitmask = 0x80;
     bitmask = bitmask >> bitToCheck;
     if (mask[byteToCheck] & bitmask)
          return(1);

     return(0);

}

bool bit_set(void* bitmask, int bitnum)
{
  return (((unsigned char*)bitmask)[bitnum >> 3] & (1 << (7-(bitnum & 7))))!=0;
}

int main()
{
     unsigned char byteArray[7]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00}; /* initialized to 0 */
     int bitCheck = 0;

     for (int g = 0; g<7; ++g)
     {
      /* set the leftmost (most significant) bit in the byte we are testing now... */
      byteArray[g] = 0x80;

      for (int h = 0; h < 8; ++h)
       {  
         int isbitSetTest = isBitSet(byteArray,bitCheck);
         bool bit_setTest = bit_set(byteArray,bitCheck);
          printf("isBitSet returned %d for byte %d bit %d\n", isbitSetTest, g, h);
          printf("bit_set  returned %d for byte %d bit %d\n", bit_setTest, g, h);

          /* increment bitCheck to the next bit offset in the array, and shift the bit within
          the current byte we are testing */
          bitCheck++;
        byteArray[g] >>= 1;
       }

       /* set it to 0 now that we are done, just in case... */
       byteArray[g] = 0x00;
     }

     return(0);
}
0
 
LVL 12

Expert Comment

by:Salte
ID: 8087335
The problem with bitmask and bit numbering is only significant in two ways as far as I know.

1. if you have more than one byte, then the endianess comes into play:

do you count:

31 30 29 ... 3 2 1 0 63 62 61 ..... 33 32 95 94...65 64 etc

or do you count

7 6 5 4 3 2 1 0 15 14 13 12 11 ..10 9 8 23 22 ... 17 16..


It really makes no sense to count the bits as:

0 1 2 3 4 5 6

where 0 is the most significant bit in this situation. The natural thing is to let bit position 0 be the least significant bit etc. You CAN count the opposite way but there's really no reason to.

The second situation is when sending bits in a bit stream out on a cable or other communication stream bit by bit. In this situation it is VERY important exactly which sequence the bits come in and so it makes a big difference if you count bit 0 to be the least significant or most significant bit.

The third situation is if you have specific hardware on the machine that can handle bit vectors and treat the bits to be in a specific sequence. In this case you just treat each bitvector as an opaque (more or less) string of bits and let the bit hardware manipulate it. so bit 0 is whatever that hardware think is bit 0 wether it is most significant or least significant bit.

So, as long as you don't do any sending of bit streams over some communication line or has specific bit hardware there's really no reason to do anything other than treating bit 0 being the least significant bit.

Memory on a typical byte addressable machine today uses bytes as the smallest addressable units and it doesn't matter which bit you consider to come first in a sequence.

If you have specific hardware then let that hardware deal with the bits as it pleases and you follow whatever that hardware decide for you.

Only in the case of communication over a serial line where you send the data bit by bit does it make a difference which bit you consider to be bit 0 or not.

so, gj62 I would say you are wrong.

It isn't odd to treat the bits as going from least significant to most significant. It is odd (but it does happen) that code treat a bit vector with bit 0 as the most significant bit. However, it is largely a matter of taste and I think when no arguments are in favor of either method the method with least significant bit being bit 0 is the 'obvious' method. This calls for least code in computing the bit mask etc:

test bit n in an array of ints:

bool is_bit_set(unsigned int arr[], unsigned int n)
{ return (arr[n >> 5] & (1 << (n & 0x1f)) != 0; }

doing anything else would cause you to have an additional subtraction in there somewhere.

If you have either bit hardware that treat bit 0 as the most significant bit or if your communication require it, that is a different matter, in that case you must follow those external conditions. All things equal the above method is the preferred however.

Alf
0
 
LVL 6

Expert Comment

by:gj62
ID: 8088507
Alf,

He's got an array of bytes (unsigned chars) - there is no endianess...

If he's got an array of unknown size, the EASIEST method of counting bits is from left to right - the same way the array grows.  Yes, you could got from right to left, but the bits no longer represent a single number, so least vs most significant is not really in play.

As I mentioned before, you kinda have to think of it as bit-offsets - at least we do.

In fact, we use the method where I am as flags in a license file to determine which features/fields/functionality each user is entitled to (encrypted, of course).

Note that I never said anyone was right, or wrong - I just said that according to the original question, it appeared as though we had bit-offsets into an array of bytes...  which is still how I read the question...
0
 

Author Comment

by:el_rooky
ID: 8089314
Thanks everyone for all your help. Both of these functions work, I was just doing something wrong yesterday. I will use your sugestion gj62.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8089614
Since smallest addressable unit in memory is in bytes, the bits within a byte doesn't have direction along the same axis as the addresses do. If any it would be the direction that comes with int values and bit positions.

Using bit position 0 = least significant bit of first byte is in no way 'unnatural' or whatever you wanna call it. In fact it is very natural.

Alf
0
 
LVL 6

Expert Comment

by:gj62
ID: 8089776
Alf,

I guess we are going to agree to disagree.

Again, your statement about endianess has no bearing, since it is any array of unsigned char.  

If you think about an array, you think about it growing in natural numeric progression from left to right - that's all I was saying.

The math is trivial in either account - the application seems to be using this as flags, so one more subtraction is of little consquence.

Quite frequently, we end up examining the "bit arrays" in memory diplayed in a debugger, or in a hex editor once they are written to a file.  It is easier to find the 31st bit if you simply count from left to right, rather than having the byte offsets go from left to right, and the bit offsets from right to left in each byte.

I submit it is a matter of style, and there is no right or wrong way when you are thinking of this as a bit-array.

For any other purpose, I agree that bit location is from least to most significant...
0
 
LVL 12

Expert Comment

by:Salte
ID: 8089992
The point is that because it is a unit of bytes, the bit ordering is COMPLETELY IRRELEVANT.

The only situation the bit ordering would matter would be:

a) you have int or short or some size larger than char and you grab bits from it.

b) you send the data to some form of communication device that takes data bit by bit.

c) You have some external requirements that the bit sequence must have one particular ordering and not any other.

If neither of these conditions are met he can choose to order his bits any way he wants, there is no ordering that is more or less unatural per se.

However, the natural ordering then is whatever is simplest in code, and if you can simply and say:

bool is_bit_set(unsigned char * vec, int x)
{  return (vec[x >> 3] & (1 << (x & 7))) != 0; }

Then that is more natural than:

bool is_bit_set(unsigned char * vec, int x)
{  return (vec[x >> 3] & (1 << (7-(x & 7)))) != 0; }

Here you must do an extra subtraction, so it is not so natural as the first solution.

And stating that it makes more sense to regard a bit vector with the bits going the other way is very much a matter of viewpoint. you THINK it is more natural because this is the way you EXPECT it to be. People who aren't biased in their expectations doesn't suffer from such illusions. It is just as natural to read a bit stream of:

11000101 10011100 etc... where the bits are read left to right as:

0b10100011 00111001 ...etc...
0xa3 0x39 etc...

as it is to read it as:

0xc5 0x9c etc ...

In either case do you have to do some conversion from hex to bits to get a picture of the vector. The reversing of 8 bits per byte is the simplest operation.

How often do you read bit streams? Not often, the few times you do it I am sure you can switch those bits. How often is your bit vector going to index and do that extra subtraction because you once every now and then want to read the stream the way you want to see it? Probably millions of times.

Now, when it comes to 'more than a byte' which I know isn't his situation, it is a different matter. Then we also have endianess and the bytes may come in any order. Some people have problems reading intel hex dumps because a number such as 0x3745 is stored as 0x45 0x37 etc. However, the reason why they chose this endianess is because it has other advantages. For example a value such as 0x0045 would be 0x45 0x00 and you can either look upon that value as a byte or as a short and it is correct in either case.

If you choose the other style which motorola and many other CPUs uses:

0x3745 is stored as 0x37 0x45.

It is probably easier to read but if you consider 0x0045 again you see it is 0x00 0x45 and to reach the byte you now have to modify the address, the byte is stored at a different address.

Both methods has their pros and cons. Similarly, selecting left-to-right or right-to-left bit ordering in a byte in a bit vector has their pros and cons, both methods. However, the pro for having most significant bit as bit 0 is "easier to read if you translate the hex to bits and write left to write" and the con is "need to do more arithmetic to get the access the bit".

I would say the con is more significant than the pro, you disagree and I guess we can agree to disagree on that. I tend to execute bit access far more often than I read bit vector hex dumps and when I read them I can always switch it around in my head in the same way I switch around the bytes for endianess.

Alf
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses
Course of the Month12 days, 20 hours left to enroll

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question