user1027508
user1027508

Reputation: 151

How does BitConverter.ToInt32 work?

Here is a method -

using System;

class Program
{
    static void Main(string[] args)
    {
        //
        // Create an array of four bytes.
        // ... Then convert it into an integer and unsigned integer.
        //
        byte[] array = new byte[4];
        array[0] = 1; // Lowest
        array[1] = 64;
        array[2] = 0;
        array[3] = 0; // Sign bit
        //
        // Use BitConverter to convert the bytes to an int and a uint.
        // ... The int and uint can have different values if the sign bit differs.
        //
        int result1 = BitConverter.ToInt32(array, 0); // Start at first index
        uint result2 = BitConverter.ToUInt32(array, 0); // First index
        Console.WriteLine(result1);
        Console.WriteLine(result2);
        Console.ReadLine();
    }
}

Output

16385 16385

I just want to know how this is happening?

Upvotes: 15

Views: 17327

Answers (6)

Kind Contributor
Kind Contributor

Reputation: 18563

You can look for yourself - https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs,e8230d40857425ba

If the data is word-aligned, it will simply cast the memory pointer to an int32.

return *((int *) pbyte);

Otherwise, it uses bitwise logic from the byte memory pointer values.

Upvotes: 0

Zapnologica
Zapnologica

Reputation: 22556

For those of you who are having trouble with Little Endien and Big Endien. I use the following wrapper functions to take care of it.

    public static Int16 ToInt16(byte[] data, int offset)
    {
        if (BitConverter.IsLittleEndian)
        {
            return BitConverter.ToInt16(BitConverter.IsLittleEndian ? data.Skip(offset).Take(2).Reverse().ToArray() : data, 0);
        }
        return BitConverter.ToInt16(data, offset);
    }

    public static Int32 ToInt32(byte[] data, int offset)
    {
        if (BitConverter.IsLittleEndian)
        {
            return BitConverter.ToInt32(BitConverter.IsLittleEndian ? data.Skip(offset).Take(4).Reverse().ToArray() : data, 0);
        }
        return BitConverter.ToInt32(data, offset);
    }

    public static Int64 ToInt64(byte[] data, int offset)
    {
        if (BitConverter.IsLittleEndian)
        {
            return BitConverter.ToInt64(BitConverter.IsLittleEndian ? data.Skip(offset).Take(8).Reverse().ToArray() : data, 0);
        }
        return BitConverter.ToInt64(data, offset);
    }

Upvotes: -1

Brian
Brian

Reputation: 25834

Looking at the .Net 4.0 Framework reference source, BitConverter does work how Jon's answer said, though it uses pointers (unsafe code) to work with the array.

However, if the second argument (i.e., startindex) is divisible by 4 (as is the case in your example), the framework takes a shortcut. It takes a byte pointer to the value[startindex], casts it to an int pointer, then dereferences it. This trick works regardless of whether IsLittleEndian is true.

From a high level, this basically just means the code is pointing at 4 bytes in the byte array and categorically declaring, "the chunk of memory over there is an int!" (and then returning a copy of it). This makes perfect sense when you take into account that under the hood, an int is just a chunk of memory.

Below is the source code of the framework ToUint32 method:

return (uint)ToInt32(value, startIndex);

Upvotes: 3

Security Hound
Security Hound

Reputation: 2551

array[0] = 1; // Lowest // 0x01
array[1] = 64; // 0x40
array[2] = 0; // 0x00
array[3] = 0; // Sign bit 0x00

If you combine each hex value 0x00004001

The MSDN documentatin explains everything

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500695

The docs for BitConverter.ToInt32 actually have some pretty good examples. Assuming BitConverter.IsLittleEndian returns true, array[0] is the least significant byte, as you've shown... although array[3] isn't just the sign bit, it's the most significant byte which includes the sign bit (as bit 7) but the rest of the bits are for magnitude.

So in your case, the least significant byte is 1, and the next byte is 64 - so the result is:

( 1 * (1 << 0) ) +    // Bottom 8 bits
(64 * (1 << 8) ) +    // Next 8 bits, i.e. multiply by 256
( 0 * (1 << 16)) +    // Next 8 bits, i.e. multiply by 65,536
( 0 * (1 << 24))      // Top 7 bits and sign bit, multiply by 16,777,216

which is 16385. If the sign bit were set, you'd need to consider the two cases differently, but in this case it's simple.

Upvotes: 16

Toto
Toto

Reputation: 149

It converts like it was a number in base 256. So in your case : 1+64*256 = 16385

Upvotes: 4

Related Questions