【问题标题】:Bit Twiddling: Encoding Unsigned PrimitivesBit Twiddling:编码无符号基元
【发布时间】:2014-01-27 20:05:02
【问题描述】:

下面是一个将 unsigned 原始类型编码为字节数组并将编码字节数组作为十进制字符串返回的类。我从概念上理解 encodeIntBigEndianbyteArrayToDecimalString 的工作原理。但是,我希望您能清楚说明:

  1. 为什么/如何将val 移动((size - i - 1) * Byte.SIZE) 会产生一个无符号Java 字节值。
  2. 另外,为什么应用0xff 的字节掩码会将字节转换为十进制字符串值。
public class BruteForceCoding {
 private static byte byteVal = 101; // one hundred and one
 private static short shortVal = 10001; // ten thousand and one
 private static int intVal = 100000001; // one hundred million and one
 private static long longVal = 1000000000001L;// one trillion and one

 private final static int BSIZE = Byte.SIZE / Byte.SIZE;
 private final static int SSIZE = Short.SIZE / Byte.SIZE;
 private final static int ISIZE = Integer.SIZE / Byte.SIZE;
 private final static int LSIZE = Long.SIZE / Byte.SIZE;

 private final static int BYTEMASK = 0xFF; // 8 bits
 public static String byteArrayToDecimalString(byte[] bArray) {
  StringBuilder rtn = new StringBuilder();
  for (byte b : bArray) {
   rtn.append(b & BYTEMASK).append(" ");
  }
  return rtn.toString();
 }

 public static int encodeIntBigEndian(byte[] dst, long val, int offset, int size) {
  for (int i = 0; i < size; i++) {
   dst[offset++] = (byte) (val >> ((size - i - 1) * Byte.SIZE));
  }
  return offset;
 }

 public static void main(String[] args) {
  byte[] message = new byte[BSIZE + SSIZE + ISIZE + LSIZE];
  // Encode the fields in the target byte array
  int offset = encodeIntBigEndian(message, byteVal, 0, BSIZE);
  offset = encodeIntBigEndian(message, shortVal, offset, SSIZE);
  offset = encodeIntBigEndian(message, intVal, offset, ISIZE);
  encodeIntBigEndian(message, longVal, offset, LSIZE);
  System.out.println("Encoded message: " + byteArrayToDecimalString(message));
 }
}

【问题讨论】:

    标签: java bit-manipulation


    【解决方案1】:

    1) 它本身不会。它所做的是将值向下移动一个字节为单位。但是,当与丢弃高位的 (byte) 的强制转换结合使用时,这相当于从值中提取单个字节的移位和掩码操作。

    2) 它没有。它屏蔽了高位,留下了值的低八位(一个字节)——与在前一种情况下转换为byte 执行的操作相同。但是,默认情况下,将字节呈现为字符串会生成一个包含十进制数的字符串,表示其二进制值(从 0 到 255),并且在调用 .append() 时会隐式发生这种情况。

    【讨论】:

    • 那么,如果我理解应用0xFF11111111 字节掩码会清除较高位——本质上是在转换为二进制值的十进制字符串表示形式期间否定隐式应用的符号?
    • 是的。例如,0xFFFE(除最低位外全为 1)是 -2 的 2 补码表示。将其与 0xFF 进行按位与运算将产生 0x00FE,即 254 的 2 补码表示。高位是 2 补码整数中的符号位这一事实对于位旋转没有意义。
    【解决方案2】:

    为什么/如何将 val 移动 ((size - i - 1) * Byte.SIZE) 会产生一个无符号的 java 字节值。

    它没有。 &gt;&gt;sign extending shift 所以它不会改变左参数的符号。 &gt;&gt;&gt; 通过非零位数保证产生非负结果,因此可以考虑具有无符号输出。

    无论哪种方式,只要将其转换为 byte,该值就会再次被签名,因为 Java 没有无符号字节类型。

    另外,为什么应用 0xff 的字节掩码会将字节转换为十进制字符串值。

    没有。

    十进制转换发生在

    rtn.append(b & BYTEMASK).append(" ")
    

    (b &amp; BYTEMASK) 的类型为 int,因为 type-promotion 是 [0, 256) 范围内的值,StringBuilder.append(int)documented 作为其参数的十进制表示形式。


    更新:

    了解

    for (int i = 0; i < size; i++) {
      dst[offset++] = (byte) (val >> ((size - i - 1) * Byte.SIZE));
    }
    

    考虑它对 4 的 size 的作用,它对应于 4 字节/32 位 java int

    dst[offset  ] = (byte) (val >> 24);  // (byte) 0x??????01 == 0x01
    dst[offset+1] = (byte) (val >> 16);  // (byte) 0x????0123 == 0x23
    dst[offset+2] = (byte) (val >>  8);  // (byte) 0x??012345 == 0x45
    dst[offset+3] = (byte) (val >>  0);  // (byte) 0x01234567 == 0x67
    

    所以给定 int 0x01234567 它将按顺序将字节 0x01 0x23 0x45 0x67 放入 dst

    【讨论】:

    • encodeIntBigEndian 应该模拟写入ByteArrayOutputStream。我知道该方法将值向右移动一个字节,然后清除高位,但是这样做在将值编码为字节方面有什么作用?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多