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
Ответ 4
Если вы уже используете Guava (что вам нужно), эта проблема уже решена.