Using bit flags and bit-wise operations or converting decimal to binary in ASP/VBScript

10/18/2010 | By | 9 Replies More


I was recently working on a project in Classic ASP where I wanted to use a 32 bit number as 32 separate Boolean flags. Of course in order to do this I had to be able to convert a 32 bit decimal number to binary, change the bits to the way I wanted and convert it back to decimal to store as a long integer. This sounds like more trouble then it’s worth but there is a very simple way of doing it. I’ve written two functions for this purpose. The first can check the state of any bit in a 32 bit long integer and the other can set the state of any bit in a 32 bit long integer. This can come in handy in many situations for example if you were creating a message forum you could use this technique to store and check what permissions a user has. It’s makes for a much cleaner database to store 32 permissions in a single field.

UPDATE: I have added new functions like Left and right shifts, Left and right Rolls, Signed Right Shifts and more. The newer functions will work with Long Integers, Integers and Bytes. If you want to see them instead then Click Here

' EXAMPLE OF HOW YOU MIGHT USE THESE FUNCTIONS
' IN A MESSAGE FORUM FOR USER PERMISSIONS.

' Setting up permission name constants with their bit position. (Max = 32)
CONST CAN_POST = 1
CONST CAN_EDIT = 2
CONST CAN_READ = 3
CONST CAN_MODERATE = 4

'Example setting permissions
Dim User_Permissions
User_Permissions = 0
User_Permissions = SetBit(User_Permissions, CAN_POST, True)
User_Permissions = SetBit(User_Permissions, CAN_EDIT, False)
User_Permissions = SetBit(User_Permissions, CAN_READ, True)
User_Permissions = SetBit(User_Permissions, CAN_MODERATE, False)

'Example checking permissions
If GetBit(User_Permissions, CAN_READ) Then
     'Show user the Post
Else
     'Don't show user the post
End If

Anyway, here are my two VBScript functions.
Feel free to use them, modify them and distribute them however you like.
If you are going to use them, all I ask is that you to post a comment so I know they helped you.

Function GetBit(lngValue, BitNum)
     Dim BitMask
     If BitNum < 32 Then BitMask = 2 ^ (BitNum - 1) Else BitMask = "&H80000000"
     GetBit = CBool(lngValue AND BitMask)
End Function

Function SetBit(lngValue, BitNum, NewValue)
     Dim BitMask
     If BitNum < 32 Then BitMask = 2 ^ (BitNum - 1) Else BitMask = "&H80000000"
     If NewValue Then
          SetBit = lngValue OR BitMask
     Else
          BitMask = NOT BitMask
          SetBit = lngValue AND BitMask
     End If
End Function

How the GetBit() and SetBit() functions work.

GetBit() is pretty straight forward. You feed it a long integer and a bit location and it will return True if the bit is a 1 or false for a 0. The first thing it does is generate a bit mask which is just a number that when represented in binary is all zeros except for the bit that we are working with. So if you wanted to check bit 7 it would become decimal value 64 which in binary would be 00000000000001000000. If the bit number was 32 I set the bit mask manually in Hexadecimal to “&H80000000” which in binary would be a 1 with 31 zeros. The reason I did that is because the script was getting overflow errors when calculating it the same way as the others.

Now that we have our bit mask all we need to do is use “AND” to find out if our bit is a 1 or 0. All AND does is compare two numbers in binary. If both numbers have a 1 in the same bit position then the number it returns will have a 1 in that position otherwise it will have a 0.

For Example

Decimal number 123456789 in Binary is:-00000111010110111100110100010101
With Decimal 256 (bit 9) as a mask:----00000000000000000000000100000000
Result --------------------------------00000000000000000000000100000000

The only position they both share a 1 in is bit 9 so our result is the same as our bit mask. If bit 9 was a 0 our result would be all zeros. If you use the CBool() function on the result it will be true unless every bit is a zero.

SetBit() needs a long integer, a bit location and a value to set it to [True or 1] or [False or 0]. It will return a new long integer with the bit changed. It uses the same bit mask as GetBit(). To set a bit to 1 it works just like GetBit() except that it uses OR instead of AND. OR will set bits to a 1 if either number has a bit set to a 1 in any given position. So imagine that in the example above bit 9 was not a 1 for decimal number 123456789. The result would still have it set as a one as well as every other bit that was already a 1 because of the 1 in the same location in the mask.

Example Binary:------------------------00000111010110111100110000010101
With Decimal 256 (bit 9) as a mask:----00000000000000000000000100000000
Result --------------------------------00000111010110111100110100010101

To set a bit to a 0 is a little different. First we have to use NOT on our mask which inverts all of the bits.
After we use NOT on the mask to invert it, we use AND on the new mask and our long integer to only return 1’s where both numbers have 1’s. So you can see that bit 9 will get turned off because it’s a zero in the mask and a 1 in our long integer.

Decimal 256 after NOT-------11111111111111111111111011111111
Decimal number 123456789----00000111010110111100110100010101
Result ---------------------00000111010110111100110000010101

Anyway, this is a quick and easy way to work with bits in VBScript. I wrote these functions for Long Integers but they will probably work on smaller integer types as well.

I’m also very impressed with the free copy of SyntaxHighlighter that I’m using. If you would like to display source code on your web site you should check it out.

SyntaxHighlighter Evolved Plug-in for WordPress

Original SyntaxHighlighter for everything else

Tags: , , ,

Category: Classic ASP, Internet

About the Author ()

Comments (9)

Trackback URL | Comments RSS Feed

  1. Bob says:

    One question I have: What happens if only the sign bit gets set to true (bit 31), and the rest are 0? Could a long integer be stored (on disk) with the value of -0? Or would would this provoke an error? I trying to understand how this would work, or if it would.

    Thanks,
    Bob

    • Chris says:

      With only the sign bit set to 1 on a 32bit number it will be equal to -2147483648.

      When the sign bit is a 1 then the number is negative. in binary negative numbers are a little different. To figure out the value you treat the 0’s as 1’s and vice versa.

      So for a signed 8bit number 10000000 = -127 while 11111110 = -1

      Hope this helps.

      • Bob says:

        Chris:

        Thank you for your response. It surely helped me to better understand this subject. My research into this, including my question to you went into building a class that manipulates bits in Long integers and Currency variables. The result can be found here:

        http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=74641&lngWId=1

        If you get a chance to look at it, and comments, criticisms or improvements would be welcome. I am still looking for ways to improve it.

        Thanks again, Bob

  2. Bert says:

    Brilliant! Thank you very much, exactly what I needed

  3. madison says:

    This helped immensely! Your functions saved me a lot of time!

  4. Titus says:

    Helped, Thank you

  5. hi says:

    Helped!

  6. Curtis says:

    Awesome! I always did this the hard way setting my constants to the power of 2 numbers and not the positions. Much nicer. Thanks.

  7. chris says:

    I’m using this in a different way (error bit-mapping) and only using the getbit function but thank you! This does exactly what i need and very simply!

    thanks!!!!!!!!!!!!

Leave a Reply