Каков результат этих байтовых операций? - PullRequest
1 голос
/ 07 апреля 2020

Я обнаружил, что в сообщениях APDU, когда вы должны представлять число, подобное 511, вы пишете 0x01 0xFF, а не 0x1FF. И если вы хотите воссоздать число, вы выполните операцию

short number = (short) (b1<<8 | b2 & 0xFF);

, где b1 - 0x01, а b2 - 0xFF. Почему мы должны сделать эту операцию и каково значение b1 << 8 и b2 & 0xFF? Спасибо! </p>

1 Ответ

0 голосов
/ 17 апреля 2020

Сначала я переименую ваши переменные. b1 будет называться B1, а b2 имеет меньшее значение и будет называться B0 в приведенном ниже коде. Тогда от b31 до b0 будут указывать битовые позиции, потому что это то, к чему я привык. b31 будет наиболее значимой позицией целого числа, а b0 - наименее значимой позицией.

Обратите внимание, что все математические операции Java приводят к int. Это играет чертовски весело с Java картой времени выполнения, которая обычно не имеет int, но давайте продолжим объяснение.

Итак, сначала байт преобразуется в int. Если самый верхний бит B1 установлен на 1, то байт имеет отрицательное значение, а биты с b31 по b8 также будут установлены на 1. Это называется расширение знака для Java. Это происходит потому, что все целые числа в Java подписаны (за возможным исключением char, но в любом случае отсутствует в Java Card). Если этого не произойдет, вы получите другое отрицательное значение int, если значение byte было бы отрицательным.

B1 << 8 просто сдвигает все биты с позиции b7 на b0 байта (то есть все биты) в местоположение от b15 до b8 полученного целого числа. Сначала байт преобразуется в целое число, хотя.

Для расчета вы получите:

00000001                            // B1 input, 0x01
00000000_00000000_00000000_00000001 // B1 as int
00000000_00000000_00000001_00000000 // B1 shifted 8 to the left

Теперь для второй части. Что ж, сначала мы должны снова преобразовать в целое число, используя расширение знакового бита. Однако мы не можем использовать ИЛИ с предыдущим значением из-за возможного расширения знакового бита: все старшие биты от b15 до b8 будут установлены в 1! Вот почему мы маскируем все биты байта, используя побитовое И, чтобы отменить расширение знака.

11111111                            // B0 input, 0xFF (-1 decimal)
11111111_11111111_11111111_11111111 // B0 as int, with sign extension, (-1 decimal)
00000000_00000000_00000000_11111111 // B0 as int, after & 0xFF

Отлично, теперь мы ИЛИ два (XOR также будет работать, но да)

00000000_00000000_00000001_1111111  // B1 is now before B0

И, наконец, мы приводим к short:

00000001_11111111                   // which means removing the leftmost 16 bits

и вот мы здесь.

Обратите внимание, что нам не нужно выполнять трюк & 0xFF для B1, потому что мы все равно выбрасываем биты с b31 на b16, когда бросаем на короткую позицию. Поэтому не имеет значения, содержат ли они нулевой или однозначный бит.

Более читаемый вариант - в случае, если оптимизация не требуется - просто использовать makeShort с помощью путь. Скорее всего, он делает то же самое.

...