Reputation: 67
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
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
Reputation: 4552
For signed int24 use:
int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;
Upvotes: 0
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
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
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