更新到 64 位后长整数转换的溢出警告 java

overflow warnings for long to integer conversions after updating to 64 bit java

我们有一种方法可以将长格式的以毫秒为单位的日期转换为字节数组,以便我们可以将其发送到网络。

我们在 java 中使用以下方法将 long 转换为 byte。但是我们的 java 是 32 位的,因此我们将 long 转换为 4 字节的数组。

   private static byte[] longToBytes(final long value) {
        
        final byte[] bytes = new byte[4];

        for (int i = 0; i < bytes.length; ++i) {
            final int offset = (bytes.length - i - 1) * 8;
            bytes[i] = (byte) (((value & (0xff << offset)) >>> offset));
        }
        return bytes;
    }

但现在由于 java 已更新为 64 位,我们收到来自 coverity 的关于此转换的警告。该表达式使用 32 位 airthmatic 计算,然后以 long 类型使用。所以可能会发生信息丢失。

现在,我不想使用 8 个字节的字节数组,因为我不知道它会对我们的底层协议做什么以及它如何期望字节数组大小。但我想知道在什么情况下它会引起问题。日期可以是 64 位的吗? 对使用此代码可能存在的问题有任何想法吗?

自 25 多年前 java 的第一个版本问世以来,long 类型一直是 64 位。日期也一样:它一直使用 64 位值来计算自 1970 年 1 月 1 日 Unix 纪元以来的毫秒数。JVM 的目标体系结构(32/64 位)在这里不起作用。

您的新代码质量工具发出警告,在位运算中组合 int 和 long 类型可能会产生意外结果。我猜它更喜欢你把代码写成:

final long offset = (bytes.length - i - 1L) * 8L;
bytes[i] = (byte) (((value & (0xffL << offset)) >>> offset));

我担心此代码仅使用 long 日期值的最低 4 个字节。如果您使用毫秒时间戳,您将丢失此转换中的信息。例如,当前时间戳(十六进制)是 17342e07b15 并且您发送 42e07b15 作为输出。

in millliseconds we are representing the date

您可以用 4 个字节(32 位)表示哪些数字取决于接收方将它们解释为有符号数还是无符号数。

  • 一个带符号的 32 位整数从 -2147483648 到 2147483647。如果这些数字是自纪元以来的毫秒数,您可以表示从 1969-12-07T03:28:36.352Z 到 1970-01-25T20 的日期和时间: 31:23.647Z。对于大多数应用程序来说,这个范围相当狭窄。在我看来你遇到了一个非常现实的问题,我想知道它怎么会被忽视。
  • 如果数字是无符号的,日期和时间可以达到 1970-02-19T17:02:47.295Z。 50多年前了。

为了比较,现在的时间表示为自纪元以来的 1_594_564_976_456 毫秒。将此数字表示为无符号数需要 41 位,如果有符号则需要 42 位(他们说答案是 42 吗?;-) 所以至少 6 个字节。

你是对的,当接收方期望 4 个字节时发送 6 个或 8 个字节可能无法解决问题。解决方案将花费更多。