Выполнение побитовых сдвигов влево на «подписанных» данных в Java - лучше перейти на JNI? - PullRequest
5 голосов
/ 17 ноября 2010

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

Хорошо: я портирую программу на C # на Java.Программа имеет дело с растровыми манипуляциями, и поэтому большая часть данных в приложении представлена ​​как byte, 8-разрядное целое число без знака.Есть много предложений, чтобы вместо этого использовать тип данных short в Java, чтобы "имитировать" как можно ближе 8-байтовое целое число без знака.

Я не думаю, что это возможно для меня как C #код выполняет различные операции сдвига и AND с моими байтовыми данными.Например, если data является байтовым массивом, и этот блок кода существует в C #:

int cmdtype = data[pos] >> 5;
int len = (data[pos] & 0x1F) + 1;

if (cmdtype == 7)
{
    cmdtype = (data[pos] & 0x1C) >> 2;
    len = ((data[pos] & 3) << 8) + data[pos + 1] + 1;
    pos++;
}

Это не просто вопрос простого преобразования data как short и выполнения счтобы заставить его работать в Java.Что касается логики, требование, чтобы мои данные оставались в 8-битном без знака, является значительным;16-битный неподписанный будет ввернуть математику, как указано выше.Я здесь?Действительно, после того, как ранее якобы «1015 *» с 0XFF и char на Java и ранее не получали правильных результатов, я боюсь, что зашел в тупик.

Теперь, в другой частикод, я выполняю некоторые растровые пиксельные манипуляции.Поскольку это длительный процесс, я решил сделать вызов нативного кода через JNI.Недавно я понял, что там я мог бы использовать тип данных uint8_t и получить наиболее близкое представление к типу данных C # byte.

Является ли решение, позволяющее всем моим функциям, зависящим от данных, работать в JNI?Это кажется крайне неэффективным, как переписать, так и выполнить.Является ли решение повторить математику в Java, чтобы логика осталась прежней?Это кажется правильным, но может вызвать аневризму, не говоря уже о неправильной математике.

Я ценю любые и все предложения.

Ответы [ 2 ]

3 голосов
/ 17 ноября 2010

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

То есть, байт 1111 1101 (-5) при непосредственном приведении к short будетрезультат 1111 1111 1111 1101 (-5), а не 0000 0000 1111 1101 (253).Вы должны удалить ведущие с помощью операции AND при приведении:

short shortValue = ((short)(byteValue)) & 0xFF;

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

2 голосов
/ 17 ноября 2010

В Java есть оператор >>> (обратите внимание на три символа «>», а не только два) без знака оператора сдвига вправо.Это должно поддерживать как минимум смещение стиля C # вправо (старшие биты очищаются до нуля, а не заполнены знаком).

Что касается приведения к «короткому», то C # переводит все эти байты в 32-битныецелые числа до сдвига в любом случае.Единственная хитрость в том, что C # выполняет приведение без знака (просто заполняет верхние 24 бита нулями, независимо от значения бита 7).Если вы использовали приведение к короткому в Java, вы должны просто сказать что-то вроде:

short shortCast = ( (short)byteVal ) & 0xff;
short shiftedShortCast = shortCast << whatever;
...