Burak Avcı
Burak Avcı

Reputation: 67

Converting Byte Array To Int24

I am reading a file with BinaryReader.

There are data I want to pull at the address 0x37E but it is int24. So even I read 3 bytes, I can't convert it to int24.

Do you have any suggestion?

I'm using C# and am working on STFS package stuff.

Upvotes: 3

Views: 3274

Answers (5)

Kailang
Kailang

Reputation: 51

For signed int24, little endian use:

int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;

For signed int24, big endian use:

int num = (sbyte)array[0] << 16 | array[1] << 8 | array[2];

For unsigned int24, little endian use:

int num = array[0] | array[1] << 8 | array[2] << 16;

For unsigned int24, big endian use:

int num = array[0] << 16 | array[1] << 8 | array[2];

Note that for any signed int, little endian of n bytes, just list all the bytes, connect them using a '|', shift them one by one, and add (sbyte) to the last byte to make it signed:

var num = array[0] | array[1] << 8 | array[2] << 16 | ... | (sbyte)array[n] << 8*n;

For big endian, just reverse the shift order:

var num = array[n] | array[n-1] << 8 | array[n-2] << 16 | ... | (sbyte)array[0] << 8*n;

Or, of course, alternatively:

var num = (sbyte)array[0] << 8*n | array[1] << 8*(n-1) | ... | array[0];

You have to make sure that the (sbyte) is with the highest order byte (the last byte if little endian, the first byte if big endian) to get C# create the sign for the int.

Of course, for unsigned int, just remove the (sbyte).


Last thing.. the array can be byte[] or int[]. So you can do this:

var num = stream.ReadByte() | stream.ReadByte() << 8 | (sbyte)stream.ReadByte() << 16;

Where stream is a System.IO.Stream.

Upvotes: 5

DxCK
DxCK

Reputation: 4552

For signed int24 use:

int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;

Upvotes: 0

user3147064
user3147064

Reputation: 21

I have written an extension method for this problem some time ago.

public enum Endian : int {
    Little,
    Big
}

public static int ToInt32(this byte[] buffer, Endian endian = Endian.Little) {
    if (buffer.Length < 1 || buffer.Length > 4)
        throw new ArgumentException(" ... ");

    if (endian == Endian.Big)
        buffer.Reverse();

    int sum = 0;
    for (int i = buffer.Length - 1; i > -1; --i)
        sum += (buffer[i] << (i << 3));

    if ((buffer[buffer.Length - 1] & 0x80) == 0x80)
        sum |= (0xFFFFFF << (buffer.Length << 3));

    return sum;
}

public static unsafe void Reverse(this byte[] buffer) {
    fixed (byte* b = buffer) {
        byte* s, e;
        s = b;
        e = b + buffer.Length - 1;

        byte t;                
        while (s < e) {
            t = *s;
            *s = *e;
            *e = t;
            ++s;
            --e;
        }
    }
}

The Endian enum and the Reverse method are used by the ToInt32 method for Endian purposes.

The ToInt32 method has some nice benefits:

1. It's an extension method so you can call it with your byte[] object.

byte[] x = { 0xFF, 0xFF, 0x7F };
int value = x.ToInt32();

2. It's able to convert the byte array to both byte orders.

byte[] x = { 0x12, 0x34, 0x56 };
int valueLittle = x.ToInt32(Endian.Little); // Return 5,649,426
int valueBig    = x.ToInt32(Endian.Big);    // Return 1,193,046

3. It takes care of the sign bit.

byte[] x = { 0x00, 0x00, 0x80 };
x.ToInt32();           // Return -8,388,608
x.ToInt32(Endian.Big); // Return 128

I've tried to make the methods so fast as I can. Did some benchmarks and speed was good for me.
Hope this solution helps and makes the life easier. ;)

Upvotes: 2

Habib
Habib

Reputation: 223322

Just to complement @glglgl answer, in C# you can try the following:

public int ReadInt24(byte[] array, int pos)
{
    if(array == null || array.Length < 3)
       return -1; //some invalid value
    if (BitConverter.IsLittleEndian)
        return ((array[2]) + (array[1] * 256) + (array[0] * 65536));
    else
        return ((array[0]) + (array[1] * 256) + (array[2] * 65536));
}

The property BitConverter.IsLittleEndian will tell about the current Endianness

Indicates the byte order ("endianness") in which data is stored in this computer architecture.

Upvotes: 0

glglgl
glglgl

Reputation: 91119

In order to transform a byte array to an int24, you need to know the endianness of the data. This means: the information if 11 22 33 is supposed to mean 0x112233 or 0x332211.

Depending on this endianness, you can convert the data such as

int24 result_bigendian = array[0] * 65536 + array[1] * 256 + array[2] // (1)

or

int24 result_littleendian = array[2] * 65536 + array[1] * 256 + array[0] // (2)

(resp.

int24 result_littleendian = array[0] + array[1] * 256 + array[2] * 65536 // (3)

if you prefer that; note the difference to (1))

I don't know about C#; there may be an easier way to reach the goal.

Upvotes: 4

Related Questions