【问题标题】:Reverse bytes order of long反转 long 的字节顺序
【发布时间】:2017-11-11 17:53:52
【问题描述】:

我有一个long 变量,我需要颠倒它的字节顺序。例如:B1, B2, ... , B8 我应该返回一个包含B8, B7, ..., B1 的长整数。如何使用按位运算来做到这一点?

【问题讨论】:

  • 您使用的是字节序吗?

标签: java bit-manipulation bitwise-operators


【解决方案1】:

你可以使用Long.reverseBytes(long)

或者更多包含按位运算的方法,可以参考stack overflow question

这是你可能喜欢的另一种方法,我仍然推荐上面的方法,但它比按位好,因为你很容易出错。

Bytebuffer

byte[] bytes = ByteBuffer.allocate(8).putLong(someLong).array();
for (int left = 0, right = bytes.length - 1; left < right; ++left, --right) {
    byte temp = bytes[left]; 
    bytes[left]  = bytes[right]; 
    bytes[right] = temp;
}

我试图引导您远离按位解决方案,因为如果您不知道自己在做什么,它们很麻烦而且很容易搞砸......但是按位看起来像这样:

byte[] bytes = new byte[8];

// set the byte array from smallest to largest byte
for(int i = 0; i < 8; ++i) {
    byte[i] = (your_long >> i*8) & 0xFF;
}

// build the new long from largest to smallest byte (reversed)
long l = ((buf[0] & 0xFFL) << 56) |
         ((buf[1] & 0xFFL) << 48) |
         ((buf[2] & 0xFFL) << 40) |
         ((buf[3] & 0xFFL) << 32) |
         ((buf[4] & 0xFFL) << 24) |
         ((buf[5] & 0xFFL) << 16) |
         ((buf[6] & 0xFFL) <<  8) |
         ((buf[7] & 0xFFL) <<  0) ;

【讨论】:

  • Arrays.asList(bytes) 代码不起作用——Arrays.asList(bytes) 将返回一个List&lt;byte[]&gt;,而不是List&lt;Byte&gt;——它将返回一个包含一个元素的列表,整个字节数组.
  • @LouisWasserman 有趣的是,我在不同的网站上看到了几次 sn-p,所以认为它是正确的,但你是对的,它不是,我会替换它。
  • @Serdalis 您的ByteBuffer 解决方案就像一个魅力。谢谢!
【解决方案2】:

您可能希望使用Long.reverseBytes 而不是按位运算。详情请见Java Reference

否则,您可以查看Long.java 中的 JDK 源代码(JDK 文件夹中的 src.zip),但请注意 Oracle 的版权。

【讨论】:

  • 如果我不能使用Long.reverseBytes 并且需要使用按位运算怎么办?
  • @BenM 在我的回答中添加了指向 JDK 源的指针。在Long.reverseBytes 中,它是通过按位运算完成的。
【解决方案3】:

这是一个旧技巧,可用于字节序交换寄存器:

static long swapblock(long a, long mask, int shift) {
    long b1 = a & mask; // extract block
    long b2 = a ^ b1;   // extract remaining bits
    return (b1 << shift) |
           ((b2 >> shift) & mask); // mask again to clear sign extension
}

static long endianswap(long a) {
    a = swapblock(a, 0x00000000ffffffffL, 32);
    a = swapblock(a, 0x0000ffff0000ffffL, 16);
    a = swapblock(a, 0x00ff00ff00ff00ffL, 8);
    return a;
}

这个想法是逐步交换子块,直到达到您想要停止的所需级别。通过添加大小为 4、2 和 1 的交换,您可以将其更改为位镜像功能。

由于 java 中缺少无符号类型,因此只有一个棘手的问题。右移时需要屏蔽掉高位,因为符号位被移位量复制,高位用1填充(0x8000000000000000 &gt;&gt; 80xFF80000000000000)。

【讨论】:

    【解决方案4】:
    long reverse(long x){
         x = (x >> 32) | (x << 32); // step 1
         x = ((x & 0xffff0000ffff0000 ) >> 16) 
              | ((x & 0x0000ffff0000ffff ) << 16); // step 2
         x = ((x & 0xff00ff00ff00ff00 ) >> 8) 
              | ((x & 0x00ff00ff00ff00ff ) << 8); // step 3
         return x;
    }
    

    如果我们假设按位运算符在 O(1) 时间内工作,则反向函数在 O(lg(位数) ) 时间内工作。

    说明
    第 0 步:B1 B2 B3 B4 B5 B6 B7 B8
    第 1 步:B5 B6 B7 B8 B1 B2 B3 B4
    第 2 步:B7 B8 B5 B6 B3 B4 B1 B2
    第三步:B8 B7 B6 B5 B4 B3 B2 B1

    【讨论】:

      【解决方案5】:

      简单的循环回答:

      public static long byteReverse(long a) {
      
          long result = 0;
          for(int i = 0; i < 8; i++){
              // grab the byte in the ith place
              long x = (a >> (i*8)) & (0b11111111);
              result <<= 8;
              result |= x;
          }
          return result;
      }
      

      仅按位:

      public static long byteReverse(long a) {
      
          a = (a << 32) | (a >>> 32);
          a = ((a & 0xffff0000ffff0000L) >>> 16) | ((a & 0x0000ffff0000ffffL) << 16);
          a = ((a & 0x00ff00ff00ff00ffL) << 8) | ((a & 0xff00ff00ff00ff00L) >>> 8);
      
          return a;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        • 2023-03-18
        相关资源
        最近更新 更多