3

我正在使用 BinaryReader 读取文件。

我想在地址 0x37E 处提取数据,但它是 int24。所以即使我读了 3 个字节,我也无法将其转换为 int24。

你有什么建议吗?

我正在使用 C# 并且正在研究 STFS 包的东西。

4

5 回答 5

4

为了将字节数组转换为 int24,您需要知道数据的字节顺序。这意味着:信息 if11 22 33应该意味着0x112233or 0x332211

根据这种字节序,您可以转换数据,例如

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

或者

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

(分别。

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

如果您愿意的话;注意与(1)的区别)

我不了解 C#;可能有更简单的方法可以达到目标。

于 2013-06-14T14:28:38.400 回答
3

对于带符号的 int24,小端使用:

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

对于有符号的 int24,大端使用:

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

对于unsigned int24,小端使用:

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

对于unsigned int24,大端使用:

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

请注意,对于任何带符号的 int、 n 字节的端序,只需列出所有字节,使用 '|'连接它们,逐个移动它们,并将 (sbyte) 添加到最后一个字节以使其有符号:

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

对于big endian,只需反转移位顺序:

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

或者,当然,或者:

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

您必须确保(sbyte)具有最高位字节(如果是小端,则为最后一个字节,如果是大端,则为第一个字节)才能让 C# 为 int 创建符号。

当然,对于unsigned int,只需删除(sbyte)


最后一件事..数组可以是byte[]int[]。所以你可以这样做:

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

其中streamSystem.IO.Stream

于 2016-05-23T03:46:13.053 回答
2

前段时间我为这个问题写了一个扩展方法。

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;
        }
    }
}

ToInt32 方法将Endian 枚举Reverse 方法用于 Endian 目的。

ToInt32 方法有一些不错的好处:

1.这是一个扩展方法,所以你可以用你的 byte[] 对象来调用它。

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

2.它能够将字节数组转换为两个字节顺序。

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.它负责符号位。

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

我试图让这些方法尽可能快。做了一些基准测试,速度对我有好处。
希望此解决方案有所帮助并使生活更轻松。;)

于 2013-12-30T20:57:09.283 回答
0

只是为了补充@glglgl的答案,在 C# 中,您可以尝试以下操作:

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

属性BitConverter.IsLittleEndian将告诉您当前的字节序

指示数据在此计算机体系结构中存储的字节顺序(“字节序”)。

于 2013-08-12T19:21:45.180 回答
0

对于有符号的 int24 使用:

int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;
于 2014-11-28T22:04:50.083 回答