简体   繁体   English

Java位移导致负数

[英]Java bit-shift results in negative number

I am trying to make a method to use bit shifting to convert bytes to their hex (as a char) equivalent. 我试图使用位移来将字节转换为十六进制(作为char)等效的方法。 However, I am experiencing some unexpected results: some of the numbers come back as negative. 但是,我遇到了一些意想不到的结果:一些数字又回来了。 I understand that Java does not have the equivalent of unsigned integers, and I am at a loss as to how to make this work. 我知道Java没有等效的无符号整数,我不知道如何使这个工作。 Here is my code: 这是我的代码:

final static char[] hex_val = "0123456789ABCDEF".toCharArray();

public static void main(String[] args) {
    byte[] bytes = {(byte) 0x58, (byte) 0x6D, (byte) 0x8F, (byte) 0xBA, (byte) 0xF5, (byte) 0x81};

    for (int i = 0; i < bytes.length; i++) {
        System.out.println("Run: " + i);
        System.out.println("First nibble: " + hex_val[(bytes[i] >> 4)]);
        System.out.println("Second nibble: " + hex_val[(bytes[i] & 0xf)]);
    }
}

Here is the output: 这是输出:

Run: 0 First nibble: 5 Second nibble: 8 Run: 1 First nibble: 6 Second nibble: D Run: 2 运行:0首先半字节:5秒半字节:8运行:1首先半字节:6秒半字节:D运行:2

Followed by: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -8 at Test.main(Test.java:10) 接下来是:线程“main”中的异常java.lang.ArrayIndexOutOfBoundsException:-8 at Test.main(Test.java:10)

I know I can use String.format() to accomplish this, but I am not using that method because I need a method that works quickly while generating minimal garbage. 我知道我可以使用String.format()来实现这一点,但我没有使用该方法,因为我需要一个在生成最少垃圾的同时快速工作的方法。 My question for the experts is... what can I change to make this work? 我对专家的问题是......我可以改变什么使这项工作成功?

UPDATE UPDATE

I made the changes suggested by Ted Hopp, and it worked perfectly in the test method. 我做了Ted Hopp建议的修改,它在测试方法中完美运行。 I moved it over to my Android app, which converts the bytes to a MAC address into a char[] containing a formatted MAC. 我将它移动到我的Android应用程序,该应用程序将字节转换为MAC地址为包含格式化MAC的char []。 I'm no longer getting negative numbers, but I am getting what appear to be random miscalculations. 我不再得到负数,但我得到的似乎是随机误算。 Here is the method I am using: 这是我正在使用的方法:

static final char[] parser_hex_arr = "01234567890ABCDEF".toCharArray();
static final char[] parser_mac = "  :  :  :  :  :  ".toCharArray();

void parseMac() { 
    hex_sb.setLength(0);
    for (hex_counter = 0; hex_counter < 6; hex_counter++) {
        hex_sb.append(String.format("%02X", parser_packet_bytes[parser_skip + hex_counter]));
        if (!(hex_counter == 5)) {
                hex_sb.append(":");
        }
    }

    parser_mac[0] = parser_hex_arr[ (parser_packet_bytes[parser_skip] >> 4) & 0x0f ];
    parser_mac[1] = parser_hex_arr[ (parser_packet_bytes[parser_skip] & 0xf) ];
    parser_mac[3] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] >> 4) & 0x0f ];
    parser_mac[4] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] & 0xf) ];
    parser_mac[6] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2]  >> 4) & 0x0f ];
    parser_mac[7] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2] & 0xf) ];
    parser_mac[9] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3]  >> 4) & 0x0f ];
    parser_mac[10] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3] & 0xf) ];
    parser_mac[12] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] >> 4) & 0x0f ];
    parser_mac[13] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] & 0xf) ];
    parser_mac[15] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] >> 4) & 0x0f ];
    parser_mac[16] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] & 0xf) ];

    Log.i("PARSER", "StringBuilder.getString() = " + hex_sb.toString() + " | parser_mac = " + String.valueOf(parser_mac));

    formatted_mac = String.valueOf(parser_mac);
}

parser_packet_bytes is a byte[] array of bytes of a packet, parser_skip is an int containing an offset where the byte is located, and hex_sb is a StringBuilder. parser_packet_bytes是数据包的byte []字节数组,parser_skip是一个包含字节所在的偏移量的int,而hex_sb是一个StringBuilder。 The output from StringBuilder.toString() should be the same as String.valueOf(parser_mac)... but it isn't. StringBuilder.toString()的输出应该与String.valueOf(parser_mac)相同......但事实并非如此。 Here is an example: 这是一个例子:

I/PARSER (10860): StringBuilder.getString() = AC:22:0B:40:70:41 | I / PARSER(10860):StringBuilder.getString()= AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41 parser_mac = 0B:22:0A:40:70:41

I/PARSER (10860): StringBuilder.getString() = C8:F7:33:0E:7E:AF | I / PARSER(10860):StringBuilder.getString()= C8:F7:33:0E:7E:AF | parser_mac = B8:E7:33:0D:7D:0E parser_mac = B8:E7:33:0D:7D:0E

I/PARSER (10860): StringBuilder.getString() = 58:6D:8F:BA:F5:81 | I / PARSER(10860):StringBuilder.getString()= 58:6D:8F:BA:F5:81 | parser_mac = 58:6C:8E:A0:E5:81 parser_mac = 58:6C:8E:A0:E5:81

I/PARSER (10860): StringBuilder.getString() = AC:22:0B:40:70:41 | I / PARSER(10860):StringBuilder.getString()= AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41 parser_mac = 0B:22:0A:40:70:41

My next question is... why don't they match? 我的下一个问题是......他们为什么不匹配? Thanks for any ideas that you may have. 感谢您的任何想法。

This is due to sign extension. 这是由于签名延期。 Byte values are signed in Java, so anything over 0x7f is treated as a negative value. 字节值在Java中签名,因此超过0x7f的任何值都被视为负值。 The bit shift operators convert both operands to integers before doing the shift. 位移操作符在执行移位之前将两个操作数转换为整数。 You need to mask the bottom byte off after integer promotion. 您需要在整数提升后屏蔽底部字节。 For example: 例如:

((bytes[i] & 0xff) >> 4)

or 要么

((bytes[i] >> 4) & 0x0f)

instead of 代替

(bytes[i] >> 4)

java will bit extend when widening bytes to integer so you need to mask out the high order bits. 当将字节扩展为整数时,java将进行位扩展,因此您需要屏蔽高位。

    System.out.println("First nibble: " + hex_val[(bytes[i] >> 4) & 0x0f]);
    System.out.println("Second nibble: " + hex_val[(bytes[i] & 0x0f)]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM