Although you probably never need it as much as a C-programmer would, it’s not a bad idea to know how bit manipulation works. This post will tell you a bit about what bit manipulation is, why you could use it and how you are using it already (with or without knowing)
As you probably know, computers works with 2-base system called the binary system. A bit (which stands for binary digit) is simply either a 0 or a 1. A group of 8 bits is called a byte. 1024 bytes is called a kilobyte, 1024 kilobytes is 1 megabyte etc etc..
A byte can be represented in many ways:
As you probably know, computers works with 2-base system called the binary system. A bit (which stands for binary digit) is simply either a 0 or a 1. A group of 8 bits is called a byte. 1024 bytes is called a kilobyte, 1024 kilobytes is 1 megabyte etc etc..
A byte can be represented in many ways:
decimally: 65
hexadecimal: 0x41
as an ascii character: ‘A’
or as binary: 10000001
As you can see, it’s all the same value, but written differently.
Each bit in a byte has a value:
bit 0: 1
bit 1: 2
bit 2: 4
bit 4: 8
bit 5: 16
bit 6: 32
bit 7: 64
you can see that binary 10000001 means both bit 7 (on the left, we go from right to left!) is set to 1, and bit 0 is set to 1.
bit 7 = 64, bit 0 = 1.. 64+1 = 65, which happens to be the decimal value of the variable we are working on. It all seems to fit perfectly :)
Now, so much for the basics..
Meet your friends: or, xor, and
There are a few basic bit manipulation commands we can use:
or
When or-ing two bits, the outcome will be 1 if at least one bit is 1.
xor
When xor-ing two bits, the outcome will be 1 if both bits are different.
and
When and-ing two bits, the outcome will be 1 if both bits are 1.
There are some more:
not
if the bit you are not-ting is 1, the outcome will be 0, otherwise 1. (reversing the bit basically)
shift left <<
the bits will the variable will be shifted X places to the left (more later)
shift right >>
the bits in the variable will be shifted X places to the right (again, more later)
Some basic math
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
Great, but why do I care?
Suppose you have a variable that holds 16 different bits. Each bit is a “flag” that holds a special case.
$error_level = 0; // binary: 00000000
Here, the variable is called $error_level and is set to 0. This means, all the bits (flags) are 0 as well.
Now, we want to set the 3rd flag (bit 2). We know bit 2 has a value of 4, so we could just say:
$error_level = 4; // binary: 00000100
but this causes a problem: if there are already some bits set, they will be unset. So we solve this by OR-ing the flag:
$error_level = $error_level | 4; // $error_level |= 4; is the same thing actually written shorthand Now, we want to set the 3rd flag (bit 2). We know bit 2 has a value of 4, so we could just say:
$error_level = 4; // binary: 00000100
but this causes a problem: if there are already some bits set, they will be unset. So we solve this by OR-ing the flag:
Now, suppose error level is 67 (bits 0, 1 and 7 are set) and we are setting bit 2:
Since we are dealing with bits, we only
want to manipulate the bit in question, we do not care about any other
bits. This way we can. We only tell php which bit (or bits) we want to
manipulate. No other bits will be harmed in the process.
Suppose we want to make sure bit 5 is not set (we don’t know if it’s currently set or not):
Looks complicated, but let’s take a look:
the ~16 means: not 16. So every bit
that does not make up 16 will be set to 1, every other bit will be set
to 0. This is called ‘masking’ bits.
That gives us this:
Now, we are going to AND this value to our variable:
As you can see, nothing has changed.
This is because bit 5 wasn’t set in the first place. Now, let’s try it
with a $error_level value where bit 5 IS set:
As you can see, the result is the same as the original, except for bit 5 which is set to 0.
You can also set multiple bits at the same time:
You can also set multiple bits at the same time:
Now, attention paying viewers may have
noticed that when you OR-ing data, you might as well can add them up by
using +. Be very careful with this: even though this works when dealing
with bit-fields only, it does not work when flags are made of several
bits. When dealing with bit manipulation, use the bitwise operators, not
the arithmic ones.
Neat tricks with bits
In assembly this is (was) one of the quickest ways to set a variable to zero. It makes sense:
Since all bits are equal to each other, every bit will produce a zero.
$value = $value >> 1;
This will divide the value by 2.
Works for everything (odd numbers are rounded downwards).
Check quickly if a number is even or odd (without doing a divide):
This will mask the first bit (bit 0). When this bit is 1, the value is odd (check it out yourself!)
Why PHP does not do bits
You assign a variable in PHP probably this way:
This will assign the value ‘1’ to $var.
Note that you don’t specify what kind of variable it is. You assign it
as a integer, but you can also use it as a string, or as a float.
Doesn’t matter for PHP. It’s internal structure (the ZVAL) does all the
hard work for you converting things the way you want it too. That’s one
of the strengths (some say weaknesses) of PHP. As said: since you don’t
specify the type, you cannot tell PHP that $var is a single bit. PHP
simply does not work this way.
Why PHP DOES do bits
Ok, so I lied.. you can do bit
manipulation in PHP, but not really the way you’d expect. What we can
do, is use ANY variable as a value that stores bits. For instance, we
can use strings, integers, even arrays. Doesn’t matter. Bitwise
manipulation can come in handy even in PHP from time to time. It’s a
simple way of dealing with on-off flags inside either your code.
Suppose we have this:
instead of all these options (including the getters/setters), you could have one method / property:
Conclusion
Bit manipulation comes in very handy
from time to time. It can save space, speed and CAN increase readability
when used correctly. An example of bit manipulation is very easy to
spot. Just look at the error_reporting function in php: http://nl.php.net/manual/en/function.error-reporting.php. Even if you didn’t understand what was going on, I hope you do now…
This function checks whether a certain bit is set or not given a byte and an index. It returns true if the chosen bit is set. It casts the $value argument to a integer just in case. The index $n goes from left to right so the most significant bit is bit one and the least significant is bit eight. This function will only work for integers between 0 and 255 because that was all I needed at the time. It would be trivial to write either a function to separate bytes in an integer or to increase the amount of bits that this function checks. I originally had a different function here but the Internet quickly told me that there was an easier way to do this.
<?php
function check_bit($value,$n=8)
{
$value = (int)$value;
if($value & (1<<(8-$n))) { return true; }
else { return false; }
}
//Check Bit Usage Example
$test_byte1 = "4";
if( check_bit($test_byte1,2))
echo "Bit 2 is set in ".decbin($test_byte1);
else
echo "Bit 2 is not set in ".decbin($test_byte1);
?>
Here are the php bitwise operator definitions from the php documentation. Look like C much?$a & $b | And | Bits that are set in both $a and $b are set. |
$a | $b | Or | Bits that are set in either $a or $b are set. |
$a ^ $b | Xor | Bits that are set in $a or $b but not both are set. |
~ $a | Not | Bits that are set in $a are not set, and vice versa. |
$a << $b | Shift left | Shift the bits of $a $b steps to the left (each step means “multiply by two”) |
$a >> $b | Shift right | Shift the bits of $a $b steps to the right (each step means “divide by two”) |
Using Bitwise math to check flags is a great way to set user permissions
or modify page displays. However, doing the math can be complicated.
Name | Binary | Decimal |
Big_Text | 0001 | 1 |
Small_Text | 0010 | 2 |
Scarlet | 0100 | 4 |
Grey | 1000 | 8 |
To read preferences and permissions is simply. An user who prefers grey and big text would be 1001 (9 in dec). A user who likes scarlet and big text would be 0101 (5 in dec).
Now say you have a button that lets you choose big text as your preference. The first instinct would be to add 1 to the current set of flags. Lets see how this works.
if you have a user who perfers grey, but hasn't chosen a text size, his flags would be 1000 (8 in dec). Lets add 0001 (1 in dec to that):
$flags = $flags + big_text;
Evaluates as $flags = 8 + 1
Ok so now $flags is 1001 (9 in dec). Great! It worked!
But what if the user already said that he likes big text? He is already 1001.
$flags = $flags + big_text;
Evaluates as $flags = 9 + 1
Uh OH! $flags is now 1010 (10 in dec). That's not right.
We need a way to set the flag regardless of if it is on or off. The answer is Bitwise OR. OR compares two numbers bit by bit. If a bit is on in either of them, then it will be on in the result. the sybol for Bitwise OR is |.
$flags = $flags | big_text;
Now we have this:
1000 OR 0001 RETURNS 1001
1001 OR 0001 RETURNS 1001
Perfect!
How about turning it off. I'll leave it to you to see that subtraction will have similar problems to addition. Try it at home.
This time we have to do a complex little trick. We will use two operators Bitwise AND (&) and Bitwise NOT (~). We want to turn off the big text. What we do is:
$flags = $flags & ~big_text;
What this says is, "Set flags equal to the current flags AND NOT big_text. The Not technically inverses all bits.
~0001 becomes 1110.
AND compares two numbers and returns only the bits set in both.
1000 AND 1110 RETURNS 1000
1001 AND 1110 RETURNS 1000
We did it. Here is a complete page with a function to set bits:
<pre>
<?php
define ('f1', 1);
define ('f2', 2);
define ('f4', 4);
define ('f8', 8);
define('ON', 1);
define('OFF', 0);
function setflag(&$var, $flag, $set=ON ) {
if (($set == ON)) $var = ($var | $flag);
if (($set == OFF)) $var = ($var & ~$flag);
return;
}
function dbi($var){
$output = ($var & f8) ? '1' : '0';
$output .= ($var & f4) ? '1' : '0';
$output .= ($var & f2) ? '1' : '0';
$output .= ($var & f1) ? '1' : '0';
return $output;
}
$var1 = ( f8 | f2 | f1 );
echo (" " . dbi($var1). "n" );
echo ("ON " . dbi(f4). "n" );
setflag($var1, f4, ON);
echo ("IS " . dbi($var1). "n" );
echo ("n");
$var2 = ( f8 | f2 | f1 );
echo (" " . dbi($var2). "n" );
echo ("OFF " . dbi(f1). "n" );
setflag($var2, f1, OFF);
echo ("IS " . dbi($var2). "n" );
echo ("n");
echo ("n");
$var3 = ( f8 | f2 | f1 );
echo (" " . dbi($var3). "n" );
echo ("ON " . dbi((f4 | f1)). "n" );
setflag($var3, (f4 | f1), ON);
echo ("IS " . dbi($var3). "n" );
echo ("n");
$var4 = ( f8 | f2 | f1 );
echo (" " . dbi($var4). "n" );
echo ("OFF " . dbi((f4 | f1)). "n" );
setflag($var4, (f4 | f1), OFF);
echo ("IS " . dbi($var4). "n" );
echo ("n");
echo ("n");
?>
</pre>
This tutorial covers the basics of bits, bit-fields, and bit-wise operators and is written on a very basic level that everyone should be able to understand. I know a similar tutorial already exists but in my opinion it isn't very clear if the reader does not have any experience with the topic. I've also included basic examples of how bit-fields can be used in plugins. Please let me know of any errors\typos or recommendations. Also, if you've read this and are still unsure of something, please tell me so I can explain further.
What is a bit-field?
A bit-field is a series of contiguous bits within a memory cell (non-array). The number of bits in a given bit-field is determined by the number of bytes allocated for the data-type being used. By default, all bits in a bit-field are 0. When no bits are 1 in a given bit-field, the resulting value will be 0. If one or more bits are 1 within a bit-field, the resulting number will be non-zero. AMX-X has only 1 data-type which is a 4-byte cell so it is limited to 32-bits in a single bit-field. If you need to manipulate bits above 32, see the bit-field array example below.
Example of bit-field sizes:
- 1-bytes = 8 bits == 0000 0000
- 2-bytes = 16 bits = 0000 0000 0000 0000
- 4-bytes = 32 bits = 0000 0000 0000 0000 0000 0000 0000 0000
All information on a computer is stored in memory (RAM, ROM, hard-disc, flash memory, etc). At the lowest level, memory consists of many many many on-off switches (known as bits). An integer value is a result of a combination of bit(s) that are set to 1 or 0. If you see me refer to a binary number, this means the bit-representation of an integer.
Each bit cooresponds to a power of 2. For this example I will use 8 bits just as a quick example of how bits form a number. Bit-ordering (I'm not getting into endianness) is as follows: 7654 3210
The below values correspond to each of those bits. As you can see, if a given bit is 1 in a bitfield, the integer value will increased by the corresponding value for the respective power of 2.
1 === 2 power of 0 -- Stored in bits: 0000 0001 (binary representation)
2 === 2 power of 1 -- Stored in bits: 0000 0010
4 === 2 power of 2 -- Stored in bits: 0000 0100
8 === 2 power of 3 -- Stored in bits: 0000 1000
16 == 2 power of 4 -- Stored in bits: 0001 0000
32 == 2 power of 5 -- Stored in bits: 0010 0000
64 == 2 power of 6 -- Stored in bits: 0100 0000
128 = 2 power of 7 -- Stored in bits: 1000 0000
Suppose we have a variable holding the number 97, our bit-field would appear as: 0110 0001
Notice bits 1, 6, and 7 are set. We can then add each corresponding number (or 2 power of bit#) to our resulting number.
1 == 2 power of 0 -- 1
2
3
4
5
6 == 2 power of 5 -- 32
7 == 2 power of 6 -- 64
8 =
Or 2^0 + 2^6 + 2^7 = 1 + 32 + 64 = 97
What are the bit-wise operators and how do I use them?
- & - And
- | - Or
- ^ - Xor (Exclusive Or)
- ~ - Not (Or Ones-complement)
- << - Left bit-shift
- >> - Right bit-shift
Operator: &
Function: And
Description: This operator is used to check if and only if both of the corresponding bits in both operands are 1. The resulting bit-field will consist of bits (1's) that were present at the same location within both operands.
15 & 3 = 3
15 = 0000 1111
03 = 0000 0011
03 = 0000 0011
_________________
145 & 97 = 1
145 = 1001 0001
097 = 0110 0001
001 = 0000 0001
_________________
255 & 234 = 234
255 = 1111 1111
234 = 1110 1010
234 = 1110 1010
Operator: |
Function: Or
Description: This operator is used to check if one or both bits are 1 in the corresponding bit positions of the two operands. The resulting bit-field will consist of bits (1's) that were present in either of the operands for each bit location.
15 | 3 = 15
15 = 0000 1111
03 = 0000 0011
15 = 0000 1111
_________________
145 | 97 = 241
145 = 1001 0001
097 = 0110 0001
241 = 1111 0001
_________________
255 | 234 = 255
255 = 1111 1111
234 = 1110 1010
255 = 1111 1111
Operator: ^
Function: Xor (Exclusive Or)
Description: This operator is used to check where the corresponding bits in the two operands are different. The resulting bit-field will consist of bits (1's) that were opposite (0 & 1 or 1 & 0) at the same location within both operands.
15 ^ 3 = 12
15 = 0000 1111
03 = 0000 0011
12 = 0000 1100
_________________
145 ^ 97 = 240
145 = 1001 0001
097 = 0110 0001
240 = 1111 0000
_________________
255 ^ 234 = 21
255 = 1111 1111
234 = 1110 1010
021 = 0001 0101
Operator: ~
Function: Not
Description: Not takes the binary representation of a number, and turns all zeros into ones, and ones into zeros. Unlike the previous 3 bitwise operators [AND, OR, XOR], NOT takes just one operand
0000 1111 = 15
1111 0000 = ~15 = 240
_________________
1010 1010 = 170
0101 0101 = ~170 = 85
_________________
Operator: <<
Function: Left bit-shift
Description: Shift bits in operand to the left by specified bit positions.
X << Y
This will shift bits in the X operand Y bits to the left. Any bits to the left that fall out of the bit-range will be dropped. Any bits added to the right due to the shift are 0. This example assumes a 1-byte memory cell so any bits shifted left past the 8th bit are dropped; if you are using a larger memory cell (in AMXX, a cell is 4-bytes or 32-bits) these bits will not be dropped but moved past the 8th bit to bits 9-32).
15 << 4
015 = 0000 1111
030 = 0001 1110 [All bits shifted 1 position]
060 = 0011 1100 [All bits shifted 2 positions]
120 = 0111 1000 [All bits shifted 3 positions]
240 = 1111 0000 [All bits shifted 4 positions]
_________________
209 << 2
209 = 1101 0001
162 = 1010 0010 [All bits shifted 1 position]
068 = 0100 0100 [All bits shifted 2 positions]
Operator: >>
Function: Right bit-shift
Description: Shift bits in operand to the right by specified bit positions.
X >> Y
This will shift bits in the X operand Y bits to the right. Any bits to the right that fall out of the bit-range will be dropped. Any bits added to the left due to the shift are 0.
15 >> 4
015 = 0000 1111
007 = 0000 0111 [All bits right-shifted 1 position]
003 = 0000 0011 [All bits right-shifted 2 positions]
001 = 0000 0001 [All bits right-shifted 3 positions]
000 = 0000 0000 [All bits right-shifted 4 positions]
_________________
209 >> 2
209 = 1101 0001
104 = 0110 1000 [All bits right-shifted 1 position]
052 = 0011 0100 [All bits right-shifted 2 positions]
Common bit-field operations
Setting bit(s) to 1\true in a bit-field
This is done using the bit-wise OR operator |. As explained above, this will set the bit to true if it exists in either operand.
Assume an empty variable which we want to set bit 4 to true.
Set a single bit
iVariable = iVariable | ( 1 << 4 );
0000 0000 = iVariable (freshly declared, no value set)
0001 0000 = 1 << 4
0001 0000 = iVariable | ( 1 << 4 )
Set multiple bits in the same expression
iVariable = iVariable | ( ( 1 << 4 ) | ( 1 << 5 ) )
0000 0000 = iVariable
0001 0000 = 1 << 4
0010 0000 = 1 << 5
0011 0000 = iVariable | ( ( 1 << 4 ) | ( 1 << 5 ) )
Setting bit(s) to 0\false in a bit-field
This is done using a combination of bit-wise AND & and the NOT ~ operator.
Assume a bit-field with bits 4 and 5 set.
iVariable = ( ( 1 << 4 ) | ( 1 << 5 ) )
Suppose we need to set bit 4 to 0\false.
iVariable = iVariable & ~( 1 << 4 )
0011 0000 = ( ( 1 << 4 ) | ( 1 << 5 ) )
1110 1111 = ~( 1 << 4 )
0010 0000 = ( ( 1 << 4 ) | ( 1 << 5 ) ) & ~( 1 << 4 )
The same can be done for setting multiple bits to 0\false in a single expression. You only need to bit-wise OR the bits you want set to 0.
iVariable = iVariable & ~( ( 1 << 4 ) | ( 1 << 5 ) )
Using bit-fields
In a bit-field you can set bit(s) to 1, set bit(s) to 0, check if a particular bit(s) is 0/1, and utilize the integer that results from the bit-field. This makes bit-fields very useful and efficient.
Example 1, using bit-fields as a boolean
A useful application is if you want to store if a player is admin when he connects to the server. Common practice is to create an array of cells, using one cell for each player's true\false value.
Boolean array method:
PHP Code:
new bool: g_IsAdmin[33];
public client_putinserver( id )
{
g_IsAdmin[ id ] = bool: is_user_admin( id );
}
public client_disconnect( id )
{
g_IsAdmin[ id ] = false;
}
A cell is 4-bytes so using an array for this purpose requires 132 bytes of memory (33-cells times 4-bytes).
If a bit-field is used instead, you will only declare a single cell and that can store the same info but using only 4 bytes!
Bit-field method
PHP Code:
new g_IsAdmin; //Only need a single cell of memorypublic client_putinserver( id )
{
if ( is_user_admin( id ) )
g_IsAdmin |= ( 1 << ( id & 31 ) );
}
public client_disconnect( id )
{
g_IsAdmin &= ~( 1 << ( id & 31 ) );
}
In the situation explained above where player id's 2 and 6 are online admins, our bit-field would look like the below. If you are wondering why the bits are not at the shift position based on player id, refer to the ( id & 31 ) explained above.
0000 0000 0000 0000 0000 0000 0100 0100
A bonus for using bit-fields for storing boolean values is you can quickly check if any bits are set, or in this case, if any admins are online. Remember, if no bits are 1 in a given bit-field, the resulting value is 0; like-wise, if there are 1 or more bits set to 1 in the bit-field, the resulting number is non-zero.
PHP Code:
if ( g_IsAdmin )
//there are 1 or more admins onlineelse
//there are no admins
Example 2, boolean for weapon index(s)
For this example I will show how you can flag various weapons in a bit-field. This can be used in a weapon restriction plugin or any plugin that needs a true\false value for each weapon. This is possible because weapons in CS have indexes that range from 1-32. In this example we will be creating a bit-field to represent weapons CSW_SG550 [13], CSW_AWP [18], & CSW_G3SG1 [24]. The highest index for a weapon (primary\secondary) is 30 (P90) so you do not need to worry about using ( # & 31) or anything like that.
g_Weapons = ( 1 << CSW_SG550 ) | ( 1 << CSW_AWP ) | ( 1 << CSW_G3SG1 );
This is what will occur with the above operation
0000 0000 0000 0000 0000 0000 0000 0001 = 1 (How 1 is represented on the bit-level. We are going to shift this bit to each weapon index bit position)
0000 0000 0000 0000 0010 0000 0000 0000 = 1 << CSW_SG550 (1 left-shifted by CSW_SG550 [13])
0000 0000 0000 0100 0000 0000 0000 0000 = 1 << CSW_AWP (1 left-shifted by CSW_AWP [18])
0000 0001 0000 0000 0000 0000 0000 0000 = 1 << CSW_G3SG1 (1 left-shifted by CSW_G3SG1 [24])
0000 0001 0000 0100 0010 0000 0000 0000 = g_Weapons (The result)
Remember, we are using Or for the above operation which will set each bit-position to 1 if it exists in either operand. This is why g_Weapons now has each bit set in the appropriate bit-position.
Now that we have a bit-field with our desired weapons, we can then check the weapon bit with the following:
PHP Code:
if ( g_Weapons & ( 1 << CSW_AWP ) )
//weapon is in bitfield
0000 0000 0000 0000 0000 0000 0000 0001 = 1 (Number 1 represented in bits)
0000 0000 0000 0100 0000 0000 0000 0000 = 1 << CSW_AWP (Left bit-shift of 18 bits)
0000 0001 0000 0100 0010 0000 0000 0000 = g_Weapons
0000 0000 0000 0100 0000 0000 0000 0000 = Bits in the CSW_AWP [18] position do both exist so this would return true
Suppose we want to check if scout is in our bit-field. CSW_SCOUT = index 3
PHP Code:
if ( g_Weapons & ( 1 << CSW_SCOUT ) )
//That weapon is NOT in bitfield
0000 0000 0000 0000 0000 0000 0000 1000 = 1 << CSW_SCOUT (Left bit-shift of 3 bits)
0000 0001 0000 0100 0010 0000 0000 0000 = g_Weapons
0000 0000 0000 0000 0000 0000 0000 0000 = Bits in the 4th bit (1<<3) position do not both exist so this would return false
Example 3, using a bit-field for your plugins flags\options.
PHP Code:
#define MAX_PLAYERS 32
//Create a list of options that are supported by the pluginenum ( <<=1 ) _: Options{
Speed=1, // 1 << 0 or 1
AutoAim, // 1 << 1 or 1 << 1 (as value is calculated by enum)
HighJump, // 1 << 2 or 2 << 1
ExtraHP, // 1 << 3 or 4 << 1
ExtraArmor // 1 << 4 or 8 << 1}//Define an array that will keep track of each option a player currently hasnew g_Options[ MAX_PLAYERS+1 ];//Examples of how to apply option for playerg_Options[ id ] |= Speed;g_Options[ id ] |= HighJump;g_Options[ id ] |= ExtraArmor;//Example how to check if a player has an optionif ( g_Options[ id ] & Speed )
//player has speed
PHP Code:
#define MAX_PLAYERS 32
//Create options as normal enum (no bitshift)enum _:Options{
Speed, //0
AutoAim, //1
HighJump, //2
ExtraHP, //3
ExtraArmor //4}
new g_bOptions[ MAX_PLAYERS+1 ][ Options ];//Examples of how to apply option for playerg_Options[ id ][ Speed ] = true;g_Options[ id ][ HighJump ] = true;g_Options[ id ][ ExtraArmor ] true;//Example how to check if a player has an optionif ( g_Options[ id ][ Speed ] )
//player has speed
To easily manipulate bits in your plugin to work with players (or any 1-32 indexes) without having to re-write the bit operations each time, here are some macros. Remember, the max bit you can manipulate is 32 in AMX-X since the only data-type available is a 4-byte cell [32 bits].
PHP Code:
//If you are storing a player index or anything that has an index up to 32.
//Example: SetPlayerBit( BitFieldVar , # )
#define SetPlayerBit(%1,%2) (%1 |= (1<<(%2&31)))
#define ClearPlayerBit(%1,%2) (%1 &= ~(1 <<(%2&31)))
#define CheckPlayerBit(%1,%2) (%1 & (1<<(%2&31)))
//Safe for using values 0-31.
//Example: SetBit( BitFieldVar , # )
#define SetBit(%1,%2) (%1 |= (1<<%2))
#define ClearBit(%1,%2) (%1 &= ~(1<<%2))
#define CheckBit(%1,%2) (%1 & (1<<%2))
A major benefit is conserving memory and CPU but IMO they are, in most cases, easier than using an array of bools. As you saw towards the beginning of this tutorial, you save 131 bytes of memory by using a bit-field over an array for storing player boolean (true\false) values. It also can result in less code because you can quickly check if bits exist or not with a simple if-statement; using an array you would need some type of loop to check each element.
Manipulating bits outside of the bit-range of a memory cell
This can be done through the usage of a bit array. This will simply use the first array element for bits 1-32, the second element for bits 33-64, and so on. There is not max-bit limitation on a bit-array as there is with a normal bit-field.
PHP Code:
g_BitField[0] //bits 1-32g_BitField[1] //bits 33-64g_BitField[2] //bits 65-96
PHP Code:
#define SetBit(%1,%2) (%1[%2>>5] |= (1<<(%2 & 31)))
#define ClearBit(%1,%2) (%1[%2>>5] &= ~(1<<(%2 & 31)))
#define CheckBit(%1,%2) (%1[%2>>5] & (1<<(%2 & 31)))
PHP Code:
//Set the highest bit that we need to access
#define MAX_BIT 515
//Define an array large enough to contain all of the needed bits (1 -> MAX_BIT)new iBitfieldArray[ ( MAX_BIT / 32 ) + 1 ];//or you can donew iBitfieldArray[ ( MAX_BIT >> 5 ) + 1 ];//Set some random bitsSetBit( iBitfieldArray , 256 );SetBit( iBitfieldArray , 500 );//Check if the above worked successfullyif ( CheckBit( iBitfieldArray , 256 ) )
ClearBit( iBitfieldArray , 256 );
if ( CheckBit( iBitfieldArray , 20 ) )//falseClearBit( iBitfieldArray , 256 );
Experimenting with binary numbers
Pawn has a constant (0b) that allows you to work with values in binary directly. To use it, prefix a set of bits with 0b; the number 10 in bits is represented by 1010 so to store this value in a variable, you would do iVar = 0b1010. You can practice your knowledge using this if you are still uncomfortable after reading this tut. This functions identically to the hexadecimal prefix 0x that you may have seen used elsewhere.
A few more examples:
PHP Code:
i1 = 0b1;i2 = 0b10;i10 = 0b1010;i15 = 0b1111;i255 = 0b11111111;
PHP Code:
new iNum1 = 0b1011; //11new iNum2 = 0b1111; //15iResult = iNum1 & iNum2;0b1011 = iNum1; //110b1111 = iNum2; //150b1011 = iResult; //15
0 comments:
Post a Comment