0

我正在尝试将一些使用 BitConverter 的现有 C# 代码移植到 Java。我发现了各种其他线程,但后来发生在一个似乎可以解决问题的 github 类上。但是,ToUInt16 与我的 C# 代码的输出不匹配。ToInt16 和 ToInt32 似乎返回相同的值。你能帮我理解这个实现有什么问题(或者我做错了什么)吗?

代码参考:Java BitConverter

ToUInt16:

public static int ToUInt16(byte[] bytes, int offset) {
        int result = (int)bytes[offset+1]&0xff;
        result |= ((int)bytes[offset]&0xff) << 8;
        if(Lysis.bDebug)
            System.out.println(result & 0xffff);
        return result & 0xffff;
    }

ToUInt32:

public static long ToUInt32(byte[] bytes, int offset) {
    long result = (int)bytes[offset]&0xff;
    result |= ((int)bytes[offset+1]&0xff) << 8;
    result |= ((int)bytes[offset+2]&0xff) << 16;
    result |= ((int)bytes[offset+3]&0xff) << 24;
    if(Lysis.bDebug)
        System.out.println(result & 0xFFFFFFFFL);
    return result & 0xFFFFFFFFL;
}

我的代码片段:

byte[] byteArray = from some byte array
int offset = currentOffset
int msTime = BitConverter.ToUInt16(byteArray, offset)

msTime 与来自 C# 的内容不匹配

C# 示例(来自供应商的字符串使用 Convert.FromBase64String 从字符串转换)

byte[] rawData = Convert.FromBase64String(vendorRawData);
    byte[] sampleDataRaw = rawData;

    Assert.AreEqual(15616, sampleDataRaw.Length);

    //Show byte data for msTime
    Console.WriteLine(sampleDataRaw[7]);
    Console.WriteLine(sampleDataRaw[6]);

    //Show byte data for msTime
    Console.WriteLine(sampleDataRaw[14]);
    Console.WriteLine(sampleDataRaw[13]);

    var msTime = BitConverter.ToUInt16(sampleDataRaw, 6);
    var dmWindow = BitConverter.ToUInt16(sampleDataRaw, 13);
    Assert.AreEqual(399, msTime);
    Assert.AreEqual(10, dmWindow);

字节值的 C# 控制台输出:

1
143
0
10

Groovy 示例(来自供应商的字符串使用 groovy decodeBase64() 从字符串转换)

    def rawData = vendorRawData.decodeBase64()
    def sampleDataRaw = rawData
    Assert.assertEquals(15616, rawData.length)

    //Show byte data for msTime
    println sampleDataRaw[7]
    println sampleDataRaw[6]

    //Show byte data for dmWindow
    println sampleDataRaw[14]
    println sampleDataRaw[13]

    def msTime = ToUInt16(sampleDataRaw, 6)
    def dmWindow = ToUInt16(sampleDataRaw, 13)
    Assert.assertEquals(399, msTime)
    Assert.assertEquals(10, dmWindow)

**Asserts fail with** 

    399 fro msTime is actually 36609
    10 from dmWindow is actually 2560

println中字节值的Groovy输出

1
-113
0
10
4

2 回答 2

2

两种方法之间存在差异。第一个ToUInt16假设大端字节顺序。即第一个字节是最高有效字节。

ToUInt32假设小端字节顺序(一个奇怪的选择)。所以第一个字节是最不重要的。

更正的实现如下所示:

public static long toUInt32(byte[] bytes, int offset) {
    long result = Byte.toUnsignedLong(bytes[offset+3]);
    result |= Byte.toUnsignedLong(bytes[offset+2]) << 8;
    result |= Byte.toUnsignedLong(bytes[offset+1]) << 16;
    result |= Byte.toUnsignedLong(bytes[offset]) << 24;
    return result;
}

数组索引是“反转”的。

(我还将看起来很老套的位掩码更改为对 的更清晰的调用Byte.toUnsignedLong,这也是同样的事情。)

于 2017-02-21T14:53:05.677 回答
0

我实际发现的是,ToInt16 实际上给了我想要的结果,而不是解决方案中的 ToUInt16。我检查了很多结果,它们都与 .Net 输出相匹配。

我可以看到源代码的@pinkfloydx33的链接实际上是导致我尝试使用 ToInt16 而不是 ToUInt16 的原因。

于 2017-03-01T06:08:45.693 回答