24-битное целое число без знака

#javascript #c #c #byte #bit-shift

#javascript #c #c #байт #битовый сдвиг

Вопрос:

Я начинаю работать с HART (адресуемый по шоссе удаленный преобразователь) Протокол и я нашли что-то, скажем, другое, и я пытаюсь это понять, точнее, uint24. Я понимаю, что эта структура использует UInt32 внутри для хранения и большинства других общих ожидаемых функций целых чисел, поэтому использование 24-битного целого числа не сэкономит память. Но мой вопрос в том, как я могу преобразовать UInt32 в этот конкретный тип, я нашел эти строки кода в Javascript, но я не знаю, какова цель этого сдвига влево.

 var getUint24 = function(bytes)
{
    return (DataView(bytes.buffer).getUint16(0) << 8)   DataView(bytes.buffer).getUint8(0   2);
}
  

Кроме того, я нашел эту функцию, которая преобразует число в 4 байта. Я также не знаю, какова цель этих сдвигов, но, возможно, если я пойму это, я смогу создать свою собственную версию функции, которая преобразует простое число, например: 4, в его версию uint24.

 /**
 *
 * @function ToBytesInt32 "Convert number to 4 bytes (eg: ToBytesInt32(2) returns 00 00 00 02"
 * @param {number} num The input value
 * @return {byte array}
 */
function ToBytesInt32BigEndian(num) {
    if (isNaN(num)) {
        throw "ToBytesInt32 received Nan! Called from: "  
        testUtils.StrReplace.caller.toString().split('n')[0];
    }
    arr = [
        (num amp; 0xff000000) >> 24,
        (num amp; 0x00ff0000) >> 16,
        (num amp; 0x0000ff00) >> 8,
        (num amp; 0x000000ff)
    ];
    return arr;
}
  

Если кто-нибудь может помочь мне понять суть этих изменений, я бы оценил это, также очень приветствуется версия C / C .

Комментарии:

1. Обычно целое число без знака хранится в памяти в виде его шестнадцатеричного представления (сильно отличается для других типов). Сдвиг влево / вправо просто «перемещает» некоторые позиции байтов влево / вправо, заполняя новые дыры нулями и теряя перемещенные байты. Перемещение в крайнюю правую позицию дает вам уникальный байт. Маски, используемые с amp; , просто выбирают некоторые позиции, а остальные равняют нулю.

Ответ №1:

Короткий ответ

  • << сдвиг влево — это дополнение значащих битов нулями для последующего объединения в одно значение;
  • >> сдвиг вправо является частью извлечения сегмента значения в меньший тип данных (выполняется после применения маски);

Аннотация

Shift amp; sum — это способ упаковки / распаковки значений, когда кадр чтения / записи меньше длины значения. Допустим, у нас есть 4-битное значение: 1011 . И мы можем прочитать его только по 2-битным кадрам : [10], [11] .

Давайте предположим, что мы читаем поток слева направо.

 # offset 0 bits
a = stream(0)      # a = 10
a << 2             # a = 1000

b = stream (2)     # b = 11

return a   b       # 1000   11 = 1011
  

Также вам следует обратить внимание на BE/LE (большой / Маленький порядковый номер). В разных порядковых числах значение 1011 может быть представлено в потоке как 10, 11 или 11, 10 .

Пример getUint24

В случае getUint24 примера у нас есть 24-битное значение, упакованное в виде последовательности [16 bit, 8 bit] . Давайте нарисуем его так [XY, Z] , где одна буква равна 1 байту.

 # offset 0 bytes
a = DataView(bytes.buffer).getUint16(0)      # a = XY
a << 8                                       # a = XY0

# offset 2 bytes
b = DataView(bytes.buffer).getUint8(2)       # b = Z

return a   b                                 # XY0   Z = XYZ
  

И снова bytes.buffer может сохранять значение либо как [XY, Z] , либо [Z, XY] . getUintX(offset) Скрывает от нас эту информацию. Но если вы хотите написать собственный конвертер, вам нужно выяснить, какой формат используется в вашем случае.

ToBytesInt32BigEndian пример

Здесь мы видим еще одну проблему упаковки значений — применение маски.

Допустим, у нас есть 32-битное значение AB CD EF 12 . Мы можем применить маску для извлечения необходимого сегмента значения.

Например, если у нас есть 3-битное значение 011 , и мы хотели бы получить значение второго бита, нам нужно применить amp;-mask, где подлежащие биты, вычисленные по отношению 1 к исходному значению, сохраняют исходное значение, в то время как остальные биты, вычисленные против 0 , превращают любое значение в 0 .

 masked    = 011 amp; 010    # 010
bit_value = masked >> 1  # 001
  

Таким же образом с нашим ABCDEF12

 x = 0xABCDEF12 amp; 0xFF000000   # x = 0xAB000000
x >> 24                       # x = 0x000000AB
...
  

Таким образом, мы получим массив [0xAB, 0xCD, 0xEF, 0x12] . Без сдвига мы получили массив [0xAB000000, 0x00CD0000, 0x0000EF00, 0x00000012] , который не является тем, что мы хотим.