Перейти к основному содержимому

bit

LuaJIT-style побитовые операции на 32-битных целых. 12 канонических функций, все single-form lowercase (без алиасов).

Функций12
Проверено вживую12 из 12
Требуемый eventнет
Сайд-эффектынет, чистые функции
Ширина32 бита, результаты signed int32 (-2147483648..2147483647)

Только single form. Lua-стандартная конвенция: bit.band, bit.bor и т.д. Без PascalCase / camelCase алиасов. См. Обзор / Конвенция именования.

Shift counts маскируются до 5 бит. lshift(1, 32) возвращает 1 (не 0), потому что 32 & 31 = 0. То же для rshift, arshift, rol, ror. Отрицательные count тоже wrap: lshift(1, -1) = lshift(1, 31).

Краткий справочник

ФункцияСигнатураЗаметкаСтатус
band(a, b, ...) → int32побитовое И, variadic при 3+ аргументахпроверено
bor(a, b, ...) → int32побитовое ИЛИ, variadicпроверено
bxor(a, b, ...) → int32побитовое XOR, variadicпроверено
bnot(a) → int32побитовое НЕпроверено
lshift(a, n) → int32логический сдвиг влево, count маскируется до n & 31проверено
rshift(a, n) → int32логический сдвиг вправо (zero-fill)проверено
arshift(a, n) → int32арифметический сдвиг вправо (sign-extend)проверено
rol(a, n) → int32вращение влевопроверено
ror(a, n) → int32вращение вправопроверено
bswap(a) → int32swap байтового порядка (4-byte endian flip)проверено
tobit(a) → int32нормализация Lua-числа в 32-bit signed, округляет до ближайшегопроверено
tohex(a, n?) → stringhex-строка, n управляет шириной и регистромпроверено

band / bor / bxor

bit.band(a, b, ...) → int32
bit.bor (a, b, ...) → int32
bit.bxor(a, b, ...) → int32

Побитовые AND, OR, XOR. Variadic при 3+ аргументах, операция складывается слева-направо. Single-arg форма возвращает вход без изменений.

Проверено:

ВызовРезультат
bit.band(0xFF, 0x0F)15 (0x0F)
bit.band(0xFF, 0x0F, 0x03)3 (variadic)
bit.band(1)1 (single-arg = identity)
bit.bor (0x0F, 0xF0)255 (0xFF)
bit.bor (0x01, 0x02, 0x04, 0x08)15 (variadic, 4 args)
bit.bxor(0xFF, 0x0F)240 (0xF0)
bit.bxor(1, 2, 3)0 (1 ^ 2 ^ 3)
local flags = bit.bor(FLAG_A, FLAG_B, FLAG_C)
local masked = bit.band(value, 0xFF)

bnot

bit.bnot(a) → int32

Побитовое НЕ. Результат 32-bit signed.

ВызовРезультат
bit.bnot(0)-1 (0xFFFFFFFF как signed)
bit.bnot(0xFFFFFFFF)0
bit.bnot(0xFF)-256 (0xFFFFFF00)

local cleared = bit.band(value, bit.bnot(MASK))

lshift / rshift / arshift

bit.lshift (a, n) → int32
bit.rshift (a, n) → int32
bit.arshift(a, n) → int32

Shift count маскируется до низших 5 бит (n & 31), как x86 SHL/SHR/SAR инструкции и LuaJIT-семантика.

ВызовРезультат
lshift(1, 0)1
lshift(1, 4)16
lshift(1, 31)-2147483648 (sign bit)
lshift(1, 32)1 (count & 31 = 0, без сдвига)
lshift(1, 33)2 (count & 31 = 1)
lshift(1, -1)-2147483648 (count & 31 = 31)
rshift(0xFFFFFFFF, 4)268435455 (0x0FFFFFFF)
rshift(-1, 1)2147483647 (0x7FFFFFFF, zero-fill)
arshift(-1, 1)-1 (sign-extend)
arshift(0x80000000, 4)-134217728 (0xF8000000)
local hi_byte = bit.band(bit.rshift(packed, 24), 0xFF)
local signed = bit.arshift(bit.lshift(byte_value, 24), 24)

rol / ror

bit.rol(a, n) → int32
bit.ror(a, n) → int32

Биты выходящие с одного конца входят с другого. Rotation count маскируется до n & 31.

ВызовРезультат
rol(0x12345678, 8)0x34567812 (= 878082066)
ror(0x12345678, 8)0x78123456 (= 2014458966)

bswap

bit.bswap(a) → int32

Реверсирует байтовый порядок 4-байтного значения. Полезно для свопа big-endian / little-endian представлений.

Проверено: bit.bswap(0x12345678) возвращает 0x78563412 (= 2018915346).

local le_value = 0x12345678
local be_value = bit.bswap(le_value)

tobit

bit.tobit(a) → int32

Нормализует Lua-число в 32-bit signed integer.

ВызовРезультатЗаметка
tobit(0)0
tobit(2147483647)2147483647точный INT32_MAX
tobit(2147483648)-2147483648wrap через 32-bit truncation
tobit(-1)-1
tobit(0xFFFFFFFF)-1тот же bit pattern что у -1 в int32
tobit(1.7)2округляет до ближайшего, НЕ truncates
tobit округляет, не truncates

bit.tobit(1.7) возвращает 2, не 1. Если нужен truncation используй math.floor(x) перед передачей. Остальные bit.* функции принимают float и применяют ту же rounding-семантику внутри.


tohex

bit.tohex(a)            → string
bit.tohex(a, n) → string

Возвращает hex-строку. Length argument управляет и шириной поля и знаком регистра букв:

ВызовРезультат
tohex(0xABCD)"0000abcd" (default 8 chars, lowercase)
tohex(0xABCD, 4)"abcd"
tohex(0xABCD, 8)"0000abcd"
tohex(0xABCD, -4)"ABCD" (отрицательная ширина = uppercase)
tohex(0)"00000000"
tohex(-1)"ffffffff" (signed -1 = 0xFFFFFFFF)
print(bit.tohex(addr, 16))
print(bit.tohex(value, -8))

Error / edge cases

ВызовРезультат
band()"bad argument #1 to '?' (number expected, got no value)"
band(nil)то же
band("s")"bad argument #1 to '?' (number expected, got string)"
band(1)1 (single-arg возвращает вход без изменений)
bnot()"bad argument #1 to '?' (number expected, got no value)"
lshift(1)"bad argument #2 to '?' (number expected, got no value)"

bit.* функции никогда не крашатся на out-of-range вход, все coercions через tobit-семантику.


Паттерны

Упаковать четыре байта в u32

local function pack_be(b3, b2, b1, b0)
return bit.bor(
bit.lshift(b3, 24),
bit.lshift(b2, 16),
bit.lshift(b1, 8),
b0)
end
local rgba = pack_be(255, 128, 0, 255)

Распаковать packed RGBA

local function unpack_rgba(packed)
return bit.band(bit.rshift(packed, 24), 0xFF),
bit.band(bit.rshift(packed, 16), 0xFF),
bit.band(bit.rshift(packed, 8), 0xFF),
bit.band(packed, 0xFF)
end

Test, set, clear, toggle бита

local function bit_test(v, n)   return bit.band(v, bit.lshift(1, n)) ~= 0 end
local function bit_set(v, n) return bit.bor(v, bit.lshift(1, n)) end
local function bit_clear(v, n) return bit.band(v, bit.bnot(bit.lshift(1, n))) end
local function bit_toggle(v, n) return bit.bxor(v, bit.lshift(1, n)) end

Sign-extend меньшей ширины в int32

local function sign_extend(value, src_bits)
local shift = 32 - src_bits
return bit.arshift(bit.lshift(value, shift), shift)
end

print(sign_extend(0xFF, 8))
print(sign_extend(0x7F, 8))

Hex-dump значения

print(string.format("addr = 0x%s", bit.tohex(addr, -8)))