2013-08-26 3 views
3

Я пытаюсь сделать способ использования смещения битов для преобразования байтов в их шестнадцатеричный (как символ) эквивалент. Однако я испытываю некоторые неожиданные результаты: некоторые цифры возвращаются как отрицательные. Я понимаю, что Java не имеет эквивалента целых чисел без знака, и я не понимаю, как это сделать. Вот мой код:Результаты бит-сдвига Java в отрицательном числе

final static char[] hex_val = "ABCDEF".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)]); 
    } 
} 

Здесь выход:

Пробег: 0 Первый клев: 5 Второй клев: 8 Пробег: 1 Первый клев: 6 Второй грызть: D Run: 2

Далее следуют: Исключение в потоке "основного" java.lang.ArrayIndexOutOfBoundsException: -8 at Test.main (Test.java:10)

Я знаю, что могу использовать String.format(), чтобы выполнить это, но я не использую этот метод, потому что мне нужен метод, который работает быстро при создании минимального мусора. Мой вопрос для экспертов ... что я могу изменить, чтобы сделать эту работу?

UPDATE

Я сделал изменения, предложенные Ted Hopp, и он прекрасно работал в методе испытания. Я переместил его в свое приложение для Android, которое преобразует байты в MAC-адрес в char [], содержащий отформатированный MAC. Я больше не получаю отрицательные числа, но я получаю то, что кажется случайными просчетами. Вот метод я использую:

static final char[] parser_hex_arr = "ABCDEF".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 является байт [] массив байтов пакета, parser_skip является INT, содержащий смещение, где байт расположен, и hex_sb является StringBuilder. Результат из StringBuilder.toString() должен быть таким же, как String.valueOf (parser_mac) ... но это не так. Вот пример:

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

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

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

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

Мой следующий вопрос: почему они не совпадают? Спасибо за любые идеи, которые у вас могут быть.

+0

Ваше изменение - это совершенно новый вопрос (очень странное поведение тоже). Я предлагаю опубликовать его как отдельный вопрос. Новый вопрос не привлечет внимания к концу этого вопроса. (Кроме того, я не понимаю, почему это должно вести себя таким образом, вопрос требует более широкого внимания.) –

ответ

8

Это связано с расширением знака. Значения байтов подписываются в Java, поэтому ничего более 0x7f рассматривается как отрицательное значение. Операторы сдвига битов преобразуют оба операнда в целые числа перед выполнением сдвига. Вам нужно скрыть нижний байт после цельного продвижения.Например:

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

или

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

вместо

(bytes[i] >> 4) 
+0

Второй вариант - это то, что вы хотите на мой взгляд. Первый работает только потому, что он расширяет значение до 'int' в этом процессе. (Последнее тоже, но не нужно). Не так много, потому что вы все равно используете контекст 'int', но я думаю, что последнее более самодокументировано. –

+0

Java также имеет '>>>', который всегда сдвигается в нулевом бите даже по подписанным числам. –

+0

@MarkPeters - шесть из одного, полдюжины других. Оба работают из-за правил языка. –

4

Java будет немного расширить, когда расширение байта в целое, так что вам нужно, чтобы маскировать биты высокого порядка.

System.out.println("First nibble: " + hex_val[(bytes[i] >> 4) & 0x0f]); 
    System.out.println("Second nibble: " + hex_val[(bytes[i] & 0x0f)]); 
Смежные вопросы