Java: разделение целых чисел на 2 байта, а затем объединение их снова в целое число

В настоящее время я работаю над проектом, который отправляет данные из приложения Java через последовательный порт на arduino.

Проблема у меня следующая: мне нужно разбить Integer на 2 байта, а затем объединить их в Integer в Arduino. Но наоборот (Arduino- > java) только вызывает у меня проблемы. Часть arduino не так уж трудна и работает как шарм, но, несмотря на то, что я просматриваю соответствующие вопросы и ответы, уже опубликованные здесь, я не могу полностью понять, как правильно объединить байты вместе в int.

Вот код Java, который просто отказывается работать:

int in = 500;
byte[] data = new byte[2];

data[0] = (byte)(in & 0xFF);
data[1] = (byte)((in >> 8) & 0xFF);

int res = data[0] | (data[1] << 8);

Консоль распечатывается из этого:

data[0] = -12  
data[1] = 1  
res = -12

но мне нужно res, чтобы быть 500!

Ответ 1

Java использует подписанные байты (C, С++, С# работают с неподписанными), поэтому вам следует позаботиться о представлениях дополнений (для отрицательных значений):

int in = 500; 
byte[] data = new byte[2]; // <- assuming "in" value in 0..65535 range and we can use 2 bytes only

data[0] = (byte)(in & 0xFF);
data[1] = (byte)((in >> 8) & 0xFF);

int high = data[1] >= 0 ? data[1] : 256 + data[1];
int low = data[0] >= 0 ? data[0] : 256 + data[0];

int res = low | (high << 8);

Ответ 2

Проблема здесь:

int res = data[0] | (data[1] << 8);

Оператору | требуются операнды int, а data[0] продвигается от byte до int. Но поскольку как byte, так и int являются типами подписей, эта продвижение включает в себя байт -12 в целое число -12.... расширением знака.

Простейшим решением является следующее:

int res = (data[0] & 0xff) | ((data[1] & 0xff) << 8);

Здесь есть и другая проблема. В общем случае вы не можете представить int как 2 байта. Тип int имеет ширину 32 бит и требует 4 байта... для представления всего диапазона.

Ответ 3

Другая возможность - просто использовать NIO:

ByteBuffer buf = ByteBuffer.allocate(2);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putShort(500);
byte[] result = buf.array(); // [-12, 1]

buf = ByteOrder.wrap(result);
buf.order(ByteOrder.LITTLE_ENDIAN);
short res = buf.getShort(); // 500

Это имеет следующие преимущества:

  • Интеграция с Java IO - вам не нужно получать массивы - вы можете просто передать их напрямую каналам.
  • Явная спецификация заказа
  • Это в стандартной библиотеке, так как Java 1.4