2013-09-19 1 views
1

Я пытаюсь написать код, который позволит мне распечатать значение поля данных CAN-сообщений в виде ряда шорт в шестнадцатеричной форме , Поля данных CAN-сообщений содержат 4 коротких сообщения, поэтому, например, я могу распечатать одно сообщение как «FFFF EEEE ABAB 2013».Как установить 32-й бит целого числа Java, не испортив его напечатанное строковое представление

Я могу кодировать 2 коротких сообщения CAN в целочисленном значении, и все работает нормально, пока 32-й бит целого не установлен. Поскольку Java использует знаковые целые числа, установка 32-го бита заставляет его печатать серию «f» s. Я хочу, чтобы целое число выполнялось как значение без знака, поэтому его печать не вызывает проблем.

Вот пример этого происходит не так:

(int value): 0x80000000 
(string rep short 1): 0xffff8000 
<crash> 

А вот как это работает в любом другом случае:

(int value): 0x40000000 
(string rep short 1): 0x4000 
(string rep short 2): 0x0 

код, где я пытаюсь представить данные CAN сообщений и где произошел сбой:

public String getFormattedData() { 
    String dataString = ""; 

    for(String aShort : Utility.splitStringByWhitespace(getData())) { 
     try{ 
      dataString += ("0000".substring(0, 4 - aShort.length()) + aShort) + " "; 
     } catch(Exception e) { 
      System.out.println(getData()); 
      System.exit(1); 
     } 
    } 

    return dataString.toUpperCase(); 
} 

В частности, авария происходит из-за того, что «f» ударяет по длине e короткое строковое представление до 8 символов, поэтому «4 - aShort.length()» приведет к отрицательному значению, которое является недопустимым.

Edit: Для тех, кто с просьбой, в данном случае это, как я использую целые числа для кодирования данных, прежде чем я преобразовать его в строковое представление:

public String convertToCANMessageData(PWMChannel channel) { 
    int channelVal = channel.getValue(); 
    int entryDataHI = 0, entryDataLO = 0; 

    entryDataHI += channelVal << 24; 
    entryDataHI += smallData << 8; 
    entryDataHI += (largeData >> 8) & 0xFF; 
    entryDataLO += (largeData & 0xFF) << 24; 

    if(ramping) { 
     entryDataHI = entryDataHI | (1 << 16); 
    } else { 
     entryDataHI = entryDataHI & ~(1 << 16); 
    } 

    if(jumping) { 
     entryDataHI = entryDataHI | (1 << 17); 
    } else { 
     entryDataHI = entryDataHI & ~(1 << 17); 
    } 

    if(frequencySetting) { 
     entryDataHI = entryDataHI | (1 << 18); 
    } else { 
     entryDataHI = entryDataHI & ~(1 << 18); 
    } 

    return String.format("%x %x %x %x", entryDataHI >> 16, entryDataHI & 0xFFFF, 
          entryDataLO >> 16, entryDataLO & 0xFFFF); 
} 
+0

Где вы конвертировать между числами и строками? Все, что я вижу, - это много обработки строк. – Joni

+0

Как использовать длинный вместо int?Он достаточно велик, чтобы избежать проблем с символами, и вам нужно удалить только 0s –

+0

@Joni, я обновил детали. – Tagc

ответ

2

Чтобы ответить на этот вопрос в названии, чтобы установить 32-й бит в int вы можете использовать побитовое ИЛИ оператора:

myInteger |= (1 << 31); 

Если вы не хотите, чтобы это «беспорядок» строковое представление, это вопрос о том, как вы преобразовываете целое число в строку. Например, метод Integer.toHexString относится к Интс, как без знака:

print(Integer.toHexString(-3)); // output: fffffffd 

UPDATE: Используй неподписанный сдвиг влево >>> при форматировании чисел: Регулярный сдвиг влево >> распространяется знаковый бит, так что левый сдвиг отрицательного числа остается отрицательным и не «внезапно» становится огромным положительным числом.

return String.format("%x %x %x %x", entryDataHI >>> 16, entryDataHI & 0xFFFF, 
         entryDataLO >>> 16, entryDataLO & 0xFFFF); 

В качестве альтернативы вы можете использовать маскирование, которые вы уже, кажется, знакомы с:

return String.format("%x %x %x %x", (entryDataHI >> 16) & 0xFFFF, entryDataHI & 0xFFFF, 
         (entryDataLO >> 16) & 0xFFFF, entryDataLO & 0xFFFF); 
+0

Он не воспринимает их как неподписанные. FFFFFFFD - -3. –

+0

Основание FFFFFFFD 16 - 4294967293 основание 10. -3 основание 10 - -3 основание 16. – Joni

+0

FFFFFFFD - 4294967293 в базе 10, если вы считаете его неподписанным. Если вы относитесь к нему как к подписанному, то оно равно -3. -3 в дополнении 2 в базе 16 является FFFFFFFD. –

0

Я решил проблему сейчас добавив функцию полезности:

public static int parseShort(String aShort) { 
    if(aShort.length() > 4) aShort = aShort.substring(aShort.length()-4); 

    return Integer.parseInt(aShort, 16); 
} 

Если кто-нибудь получил лучшее решение, я был бы рад, чтобы отметить свой ответ, как принято, и попробовать, что из вместо.

1

Просто используйте unsigned bithift, чтобы получить верхнюю половину целого числа.

int i = 0x80000000; 
short s = (short)(i >>> 16); 
s is 0x8000 
+0

Проблема заключается в том, что я сохраняю целое число как строку, а затем пытаюсь получить целое число от него. Строковое представление 0x80000000 - это «ffff8000», и я получаю NumberFormatException, пытаясь разобрать это на целое число: Исключение в потоке «AWT-EventQueue-0» java.lang.NumberFormatException: для строки ввода: «ffffd000» – Tagc

+0

вы говорите, что я делаю, это сохранить мои ценности как шорты, прежде чем конвертировать их в строки, а затем преобразовать их в шорты, но это потребует много повторной записи. Спасибо всем тем же. – Tagc