2

Im asking this question, because couldn't find a solution for this particular case.

I need to extract value (as int or byte) from a hex string and from a given range of bits. For example:

hexString = "0x34840A00"

bits (from calc): 00110100 10000100 00001010 00000000

Now I need bits from 8 to 10: 010

Now convert to int/byte value. Any help? Im struggling with understanding of bit operations here.

PanBocian
  • 43
  • 6
  • 1
    Use the [Convert.ToInt32](https://learn.microsoft.com/en-us/dotnet/api/system.convert.toint32?view=net-5.0#System_Convert_ToInt32_System_String_System_Int32_) overload which takes the base of the from object. Like so: `int result = Convert.ToInt32("0x34840A00", 16)` – MindSwipe Aug 10 '21 at 11:54
  • I need to extract value from a bit range, not the whole hex :P – PanBocian Aug 10 '21 at 12:00
  • 1
    Without using a pure string sloution, you need to use bit mask and shift as exposed by @FrederikHoeft's answer (not checked) - [C# how convert large HEX string to binary](https://stackoverflow.com/questions/6617284/) • [How to get substring from string in c#?](https://stackoverflow.com/questions/5203052/) • [Best way to reverse a string](https://stackoverflow.com/questions/228038/) • [Convert binary string into integer](https://stackoverflow.com/questions/9149728/) –  Aug 10 '21 at 12:33

1 Answers1

2

You could first use Convert.FromHexString(hexString) to get the bytes from your hex string. Then you could either use unsafe pointers or BitConverter.ToInt32() to convert said bytes to a 32 bit integer to which you can then apply bit shifts and other bit wise operations to extract the bits you need. For example:

string hexString = "0x34840A00";
byte[] bytes = Convert.FromHexString(hexString);
int myInt = BitConverter.ToInt32(bytes, 0);
// myInt looks like this 00110100 10000100 00001010 00000000
// now shift by 8 bits to the right
myInt >>= 8;
// now it looks like this 00000000 00110100 10000100 00001010
// to get the value of the last 3 bits we need to set the first 29 bits to 0
// so we AND them together with 29 0's followed by 3 1's:
myInt &= 0x00000007;
// which results in the following bits:
// 00000000 00000000 00000000 00000010
// leaving you with an integer of the value 010 in binary or 2 in decimal

The bit shifting and AND-ing always follows the same rules:

  1. If you want the bits starting at index n (as counted from the right-most/least significant bit) then shift right by n bits (in your example n=8 (you don't care about the rightmost 8 bits)).
  2. let m be the number of bits you want to keep starting at position n (in your example you want to keep 3 bits 010). AND the result together with the integer 2^m - 1. In your example m=3 this would be 2^3-1 = 8-1 = 7. Therefore we do myInt &= 0x00000007; or in short myInt &= 0x7;.

Edit: for older .NET versions and simplifying

string hexString = "0x34840A00";
int myInt = Convert.ToInt32(hexString, 16);
// myInt looks like this 00110100 10000100 00001010 00000000
// now shift by 8 bits to the right
myInt >>= 8;
// now it looks like this 00000000 00110100 10000100 00001010
// to get the value of the last 3 bits we need to set the first 29 bits to 0
// so we AND them together with 29 0's followed by 3 1's:
myInt &= 0x00000007;
// which results in the following bits:
// 00000000 00000000 00000000 00000010
// leaving you with an integer of the value 010 in binary or 2 in decimal

The reusable (and pretty fast) approach would therefore be a method like this:

private static int GetBitsFromHexString(string hexString, int startIndexFromRight, int bitsToKeep)
{
    int result = Convert.ToInt32(hexString, 16);
    // shift by startIndexFromRight bits to the right
    result >>= startIndexFromRight;
    // AND the bits together with 32 - bitsToKeep 0's followed by bitsToKeep 1's:
    int bitmask = (1 << bitsToKeep) - 1; // is the same as 2^bitsToKeep - 1.
    // apply bitmask
    result &= bitmask;
    return result;
}

Which you would call like this in your example:

int result = GetBitsFromHexString("0x34840A00", 8, 3);
// result is 2 or 010 in binary 
Frederik Hoeft
  • 1,177
  • 1
  • 13
  • 37
  • Thank you for a solution and even more for comments in the code :) – PanBocian Aug 10 '21 at 12:07
  • One more question: my NET is older and does not have any Convert.FromHexString. By the way, did you forget to pass one more agument into BitConverter.ToInt32(bytes) (start index) ? – PanBocian Aug 10 '21 at 12:43
  • @PanBocian Oh yes you're right. The start index argument would have to be `0` in the call to `BitConverter.ToInt32`. Indeed `Convert.FromHexString()` was only introduced with .NET 5 as far as I am aware but there are lots of other questions on that here on StackOverflow :) take a look at [this question](https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa) and use one of the many ways to convert a hex string to bytes :) – Frederik Hoeft Aug 10 '21 at 12:48
  • An easier alternative to `Convert.FromHexString` and the BitConverter trickery would be to use `Convert.ToInt32("0x34840A00", 16)` as @MindSwipe mentioned in the comments. @PanBocian I updated the answer accordingly. – Frederik Hoeft Aug 10 '21 at 12:51