BitArray
The class BitArray
is a reference type that contains an array of ints, where for every 32 bits a new integer is used.
Members of this class are explained in the following table.
The helper method DisplayBits() iterates through a BitArray and displays 1 or 0 to the console,
depending if the bit is set or not:
The example to demonstrate the BitArray class creates a bit array with 8 bits,
indexed from 0 to 7. The SetAll() method
sets all 8 bits to true. Then the
Set() method changes bit 1 to false. Instead of
the Set method, you can also use an
indexer, as shown with index 5 and
7.
This is the displayed result of the initialized
bits:
The Not() method
generates the inverse of the bits of the BitArray:
The result of Not() is
all bits inversed. If the bit was true,
it is false, and if it was false, it is true:
Here, a new BitArray is
created. With the constructor, the variable bits1 is used to initialize the array, so the new
array has the same values. Then the values for bits 0, 1, and 4 are
set to different values. Before the Or()
method is used, the bit arrays bits1 and
bits2 are displayed. The Or() method changes the values of bits1.
With the Or() method,
the set bits are taken from both input arrays. In the result, the
bit is set if it was set with either the first or the second
array:
Next, the And() method
is used to operate on bits2 and
bits1:
The result of the And()
method only sets the bits where the bit was set in both input
arrays:
Finally the Xor() method
is used for an exclusive OR:
With the Xor() method,
the resultant bits are set only if the bit was set either in the
first or the second input, but not both:
BitVector32
If you know the number of bits you need in
advance, you can use the BitVector32
structure instead of BitArray.
BitVector32 is more efficient, as it is
a value type and stores the bits on the stack inside an integer.
With a single integer you have place for 32 bits. If you need more
bits, you can use a multiple BitVector32
values or the BitArray. The BitArray can grow as needed; this is not an option
with BitVector32.
The next table shows the members of BitVector that are very different from BitArray:
The sample code creates a BitVector32 with the default constructor, where all
32 bits are initialized to false. Then
masks are created to access the bits inside the bit vector. The
first call to CreateMask() creates a
mask to access the first bit. After CreateMask() is invoked, bit1 has a value of 1. Invoking CreateMask() once more and passing the first mask as
a parameter to CreateMask() returns a
mask to access the second bit, which is 2. bit3 then has a value of 4 to access bit number 3.
bit4 has a value of 8 to access bit
number 4.
Then the masks are used with the indexer to access
the bits inside the bit vector and set fields accordingly:
The BitVector32 has an
overridden ToString() method that not
only displays the name of the class but also 1 or 0 if the bits are
set or not, respectively:
Instead of creating a mask with the CreateMask() method, you can define the mask
yourself; you can also set multiple bits at once. The hexadecimal
value abcdef is the same as the binary
value 1010 1011 1100
1101 1110 1111. All the bits defined with this value are
set:
With the output shown you can verify the bits that
are set:
Separating the 32 bits to different sections can be
extremely useful. For example, an IPv4 address is defined as a
4-byte number that is stored inside an integer. You can split the
integer by defining four sections. With a multicast IP message
several 32 bit values are used. One of these 32 bit values is
separated in these sections: 16 bits for the number of sources, 8
bit for a querier’s query interval code, 3 bit for a querier’s
robustness variable, a 1-bit suppress flag, and 4 bits that are
reserved. You can also define your own bit meanings to save
memory.
The example simulates receiving the value
0x79abcdef and passes this value to the
constructor of BitVector32, so that the bits are set
accordingly.
The bits are shown on the console as
initialized:
Then six sections are created. The first section
requires 12 bits, as defined by the hexadecimal value 0xfff (12 bits are set); section B requires 8 bits;
section C, 4 bits; section D and E, 3 bits; and section F, 2 bits.
The first call to CreateSection() just
receives 0xfff to allocate the first 12
bits. With the second call to CreateSection(), the first section is passed as an
argument, so that the next section continues where the first
section ended. CreateSection() returns a
value of type BitVector32.Section that
contains the offset and the mask for the section.
Passing a BitVector32.Section to the indexer of the
BitVector32 returns an int just mapped to the section of the bit vector.
Here, a helper method, IntToBinaryString(), is used to get a string
representation of the int number:
IntoToBinaryString receives the bits in an integer
and returns a string representation containing 0 and 1. With the
implementation, 32 bits of the integer are iterated through. In the
iteration, if the bit is set, 1 is appended to the StringBuilder; otherwise, 0 is appended. Within the
loop, a bit shift happens to check if the next bit is set.
The result displays the bit representation of
sections A to F, which you can now verify with the value that was
passed into the bit vector: