3

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.

3
  • 1
    What language is this? Show us your current code (well, a SSCCE of it). And edit the question with this information rather than using the comments. Commented Jun 14, 2013 at 14:26
  • I'd suggest that you tell us about which language you talk about... Commented Jun 14, 2013 at 14:26
  • Aahhh sorry im a little bit sleepy :D Commented Jun 14, 2013 at 14:28

5 Answers 5

5

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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.

3 Comments

it is little endian so i use below one ?
exactly. Maybe (3) array[0] + array[1] * 256 + array[2] * 65536 looks better...
As (2) and (3) are semantically identical, you are free to choose amongst them.
2

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. ;)

3 Comments

Shouldnt it be int24 instead of int32?
Well, it does if you pass an byte[3]. byte[] x = { 0xff, 0xff, 0xff }; x.ToInt32(); // Returns -1 like expected
i dont have time for calculate, sorry.can you tell me if it can convert to int24 or not?
0

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.

3 Comments

i know what endianness is :D
@TCBurakAvcı, great that you know, but this answer might help future visitors like me :)
Ahh Thanks anyway.I'm trying to improve myself more :D
0

For signed int24 use:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.