vb.netbit-manipulation

Function to read a specific bit from a byte and return 0 or 1


I need a function that takes a value as a byte and a starting position as an integer, and returns a 1 or 0 as an unsigned byte, depending on whether the corresponding bit is 1 or 0.

Example 1: Decimal 100 is binary 0110 0100. If the starting position (index) is 1 (counting from the left), I expect a return of 1 because 0110 0100.

Example 2: If the starting position is 0, I expect a return of 0 because 0110 0100.

I also need the same principle applied to a function that takes a byte array.

My current issue is that the functions return the wrong result. The provided position is off by 1. I know this is the error because I tested this up to position 4. I could simply write (pos-1) to fix it, but maybe you have a better solution anyway.

In the function with the array, there is currently a 204 included in the code because I adapted the function from a C++ solution where it intentionally read beyond the array boundaries without throwing an exception. In debug mode, I kept seeing 204, no matter how often I restarted the PC.

I need this function in VB.NET. Here's my current attempt:

Option Strict On
Module Module1
    Sub Main()
        Dim result1 As Byte = GetBitByPos(100, 0)
        Dim result2 As Byte = GetBitByPos(100, 1)

        Dim result3 As Byte = GetBitByPosArray({100}, 0)
        Dim result4 As Byte = GetBitByPosArray({100}, 1)
    End Sub

    Private Function GetBitByPos(value As Byte, pos As Integer) As Byte
        Return CByte(value >> (8 - pos Mod 8) And &H1)
    End Function

    Private Function GetBitByPosArray(buffer As Byte(), pos As Integer) As Byte
        If pos \ 8 >= buffer.Length Then
            Return CByte(204 >> (8 - pos Mod 8) And &H1)
        End If
        Return CByte(buffer(pos \ 8) >> (8 - pos Mod 8) And &H1)
    End Function
End Module

Solution

  • You need to use 7 because your indices are 0...7. Also adding safety for pos overflowing the byte or array

    Private Function getBitByPos(value As Byte, pos As Integer) As Byte
        pos = pos Mod 8
        Return CByte((value >> (7 - pos)) And 1)
    End Function
    
    Private Function getBitByPosArray(buffer As Byte(), pos As Integer) As Byte
        pos = pos Mod (buffer.Length * 8)
        Return CByte((buffer(pos \ 8) >> (7 - pos Mod 8)) And 1)
    End Function
    

    Testing with

    For i = 0 To 7
        Console.Write(getBitByPos(100, i))
    Next
    Console.WriteLine()
    For i = 0 To 25
        Console.Write(getBitByPos(100, i))
    Next
    Console.WriteLine()
    Dim buffer As Byte() = {100, 255, 0, 85, 170}
    For i = 0 To (8 * buffer.Length) - 1
        Console.Write(getBitByPosArray(buffer, i))
        If ((i + 1) Mod 8 = 0) And i < (8 * buffer.Length) - 1 Then Console.Write("-")
    Next
    Console.WriteLine()
    For i = 0 To 50
        Console.Write(getBitByPosArray(buffer, i))
        If ((i + 1) Mod 8 = 0) And i < 100 Then Console.Write("-")
    Next
    

    outputs

    01100100
    01100100011001000110010001
    01100100-11111111-00000000-01010101-10101010
    01100100-11111111-00000000-01010101-10101010-01100100-111