Особенности использования битовых операций

<< Click to Display Table of Contents >>

Navigation:  Modbus Universal MasterOPC Server > Руководство по языку Lua 5.1 > Библиотеки функций > Библиотека BIT >

Особенности использования битовых операций

При использовании битовых операций необходимо учитывать особенность работы Lua с числами. При работе с битами на языке C++, Pascal, ST и прочих, происходит строгое объявление типа числа и его размерности, например - uint16 (беззнаковое короткое целое). В этом случае, если применять к данному числу любой битовый оператор, то он будет применяться только к битам размерности данного числа.

Но в Lua и для целочисленных, и для вещественных чисел выделен один тип данных - number, который представляет собой вещественное знаковое число двойной точности (double). Из-за невозможности задать размерность числа, результат может получится некорректным - это проявляется при использовании функций Логического Не и побитового сдвига влево.

Например. Рассмотрим применение оператора "Побитовое НЕ" (bit.BitNot). Допустим нам нужно выполнить инверсию битов в одном байте. Объявим переменную, и инициализируем ее например числом 10 (b00001010), а затем выполним оператор bit.Not.

local k=10;

local z=bit.BitNot(k);

Переменная z, должна получить значение 245 (b11110101), однако если выполнить данный код, то вернется число z= -11. Из-за того, что тип number - знаковый, число получилось отрицательным. Если использовать его, например, при подсчете контрольной суммы результат выйдет некорректным.

Чтобы получить корректное число, необходимо выполнить маскирование с помощью оператора "Логическое И" (bit.BitAnd) - первым оператором будет наше искомое число, а вторым - число-маску значащих байт (в нашем случае 0xFF - b11111111).

local k=10;

local z=bit.BitAnd(bit.BitNot(k),0xFF);

Теперь переменная z будет равна 245.

Похожая ситуация может возникнуть при использовании оператора сдвига влево. Например у нас есть двухбайтовое число, равное 21763  (b01010101 00000011). Сдвинем его влево на 2 бита с помощью оператора bit.BitLshift.

local k=21763;

local z=bit.BitLshift(k,2);

Должно получится число b‭01010100 00001100‬‬ - 21516, но сервер вернет 87052 - b‭0001 01010100 00001100. Что же произошло? При строгой типизации, два сдвинутых влево старших бита были бы стерты, но  поскольку в Lua тип number это вещественный двойной точности, то произошел сдвиг битов на разряды, которые нам не требуются - произошло увеличение разрядности числа. Чтобы решить данную проблему также можно применить маскирование - выполнить оператор "Логическое И", указав вторым аргументом маску значащих бит (в нашем случае 0xFFFF - b11111111 11111111).

local k=21763;

local z=bit.BitAnd(bit.BitLshift(k,2),0xFFFF);

В этом случае сервер вернет корректное число - лишние биты будут обнулены.

Просим вас учитывать данные особенности Lua при работе с указанными битовыми операторами.