【问题标题】:C# BitConverter to JavaC# BitConverter 到 Java
【发布时间】:2017-02-21 14:20:14
【问题描述】:

我正在尝试将一些使用 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

【问题讨论】:

  • 您能否提供一些失败的测试用例,以便我们可以看到对于给定输入您期望和实际得到的输出?
  • 如果有帮助,您可能需要参考 .Net 实现,该实现可在参考源 referencesource.microsoft.com/#mscorlib/system/… 中找到
  • 举个例子就好了。另外,我建议使用ByteBuffer 进行此类转换。它可以在没有库的情况下完成所有这些工作。
  • 谢谢@pinkfloydx33 我查看了文档,但没有找到源代码。我很感激。
  • 感谢@slim,我只是在线程中模拟了它,并没有考虑静态。我对其进行了调整,但会尝试提供实际示例。

标签: java bitconverter


【解决方案1】:

这两种方法之间存在差异。第一个ToUInt16 采用大端字节序。即第一个字节是最重要的字节。

但是ToUInt32 采用 little-endian 字节顺序(一个奇怪的选择)。所以第一个字节是最不重要的。

修正后的实现如下所示:

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,它的作用相同。)

【讨论】:

  • 感谢@Jorn Vernee!如果有的话,我需要对 ToUInt16 实现进行哪些更改?它还返回一个不匹配的结果。
  • @scarpacci 我需要看到minimal reproducible example。在我自己的测试代码中ToUInt16 按预期执行。
  • 听起来不错。我将努力获得一个例子。再次感谢您的帮助!
  • 我添加了测试输出,这样您就可以看到我在哪里得到了差异。再次感谢您的帮助!
  • @scarpacci 你在调用ToUInt16之前打印输出,所以问题应该出在base64解码(我以前听说过)。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多