位运算符

lua-users home
wiki

Lua 5.3+ 原生支持众所周知的位运算符。(参见 [3.4.2]

从 5.2 版本开始,Lua 附带了 [bit32] 库,该库增加了对位操作的支持。早期版本的 Lua 不包含位运算符,但 bit32 已向后移植到 5.1 版本。此外,还有用于此的 Lua 库以及一些 Lua 的修补版本。

Lua 中位运算符的实现

LuaBitOp (版本 1.0.1) 描述

bit.tobit(x)          -- normalize number to the numeric range of
                      -- bit operations (all bit ops use this implicitly)
bit.tohex(x[,n])      -- convert x to hex with n digits (default 8)
bit.bnot(x)           -- bitwise not of x
bit.band(x1[,x2...])  -- bitwise and of x1, x2, ...
bit.bor(x1[,x2...])   -- bitwise or of x1, x2, ...
bit.bxor(x1[,x2...])  -- bitwise xor of x1, x2, ...
bit.lshift(x, n)      -- left-shift of x by n bits
bit.rshift(x, n)      -- logical right-shift of x by n bits
bit.arshift(x, n)     -- arithmetic right-shift of x by n bits
bit.rol(x, n)         -- left-rotate of x by n bits
bit.ror(x, n)         -- right-rotate of x by n bits
bit.bswap(x)          -- byte-swap of x (little-endian <-> big-endian)

bitlib (版本 25) 描述

bit.bits           -- number of bits usable in bitwise operations
bit.bnot(a)        -- returns the one's complement of a
bit.band(w1, ...)  -- returns the bitwise and of the w's
bit.bor(w1, ...)   -- returns the bitwise or of the w's
bit.bxor(w1, ...)  -- returns the bitwise exclusive or of the w's
bit.lshift(a, b)   -- returns a shifted left b places
bit.rshift(a, b)   -- returns a shifted logically right b places
bit.arshift(a, b)  -- returns a shifted arithmetically right b places
bit.cast(a)        -- cast a to the internally-used integer type

bitlib 是用 C 语言实现的。内部,每个位数组实现为一个整数类型。MIT 许可。

adt.bits (2009-04)

bits.create(value, number)     -- return bitmap of given size set to value
bits:set(value)                -- set all bits to value, return bitmap
bits:set(value, n1[,n2[n3,...]]) -- set these bits to value, return bitmap
bits:get(n)                    -- get value of this bit
bits:get(n1[,n2[n3,...]])      -- get value of these bits
bits:iterator()                -- return iterator for all bits => i,v
bits:iterator(n)               -- return iterator starting at bit n => i,v
bits:iterator(n1, n2)          -- return iterator over range [n1..n2] => i,v
bits:index(value)              -- return iterator => next index with the value
bits:index(value, start)       -- return index of next bit with the value
bits:isequal(b)  bits == b     -- return true or false for equality
bits:notbits()   - bits        -- return NOT of the bitmap
bits:orbits(b)   bits + b      -- return OR of the bitmaps
bits:andbits(b)  bits * b      -- return AND of the bitmaps
bits:xorbits(b)  bits % b      -- return XOR of the bitmaps
bits:orbits(n1, n2[, n3,...])  -- return OR of these bits
bits:andbits(n1, n2[, n3,...]) -- return AND of these bits
bits:xorbits(n1, n2[, n3,...]) -- return XOR of these bits
bits:copy()                    -- return a copy of the bitmap
bits:printlimit()              -- return current limit
bits:printlimit(n|"all"|"*")   -- set n or all bits printed, return new limit
bits:size(), #bits             -- return the bit capacity
bits:ones()                    -- return the number of 1 bits
bits.version()                 -- return the version of module

Lua 中迭代位 描述

function bit(p)
  return 2 ^ (p - 1)  -- 1-based indexing
end

-- Typical call:  if hasbit(x, bit(3)) then ...
function hasbit(x, p)
  return x % (p + p) >= p       
end

function setbit(x, p)
  return hasbit(x, p) and x or x + p
end

function clearbit(x, p)
  return hasbit(x, p) and x - p or x
end

这更像是一种设计模式,而非实际的库。它用 Lua 实现。内部,每个位数组实现为一个 Lua number。上述的原始操作提供了在 number 中测试/设置/清除位的简单代码。位操作可以根据这些函数来定义。

LuaBit (版本 0.4) 描述

bit.bnot(n) -- bitwise not (~n)
bit.band(m, n) -- bitwise and (m & n)
bit.bor(m, n) -- bitwise or (m | n)
bit.bxor(m, n) -- bitwise xor (m ^ n)
bit.brshift(n, bits) -- right shift (n >> bits)
bit.blshift(n, bits) -- left shift (n << bits)
bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)

LuaBit 完全用 Lua 实现。内部,每个位数组实现为一个 Lua number 或一个 Lua 数字数组。此包还包括将 number 转换为/从十六进制字符串的函数,一个用于 UTF8 -> UCS2 字符串转换的 'utf8' 模块,以及一个与诺基亚 PC 相关的 'noki' 模块。MIT 许可。

BinDecHex (2007-10) 描述

Hex2Bin(s)
Bin2Hex(s)
Hex2Dec(s)
Dec2Hex(s)
Bin2Dec(s)
Dec2Bin(s [, num])
BMAnd(v, m)
BMNAnd(v, m)
BMOr(v, m)
BMXOr(v, m)
BMNot(v, m) 

BinDecHex 完全用 Lua 编写。内部,每个位数组实现为大端格式的 Lua 字符串。BSD 许可。

BitUtils 描述

BitUtils 提供了一些完全用 Lua 实现的杂项代码片段。内部,一般来说,每个位数组实现为一个 Lua number。

位运算符 Power Patch 描述

Infix bitwise operators for AND (&, __and), OR (|, __or), XOR (^^, __xor).
Infix bitwise operators for SHIFT LEFT (<<, __shl) and SHIFT RIGHT (>>, __shr).
Unary bitwise negation operator (~, __not).
Infix arithmetic operator for INTEGER DIVISION (\, __intdiv).
    accepts both ~= and != for comparison. 

这作为 Lua 的一个补丁实现。内部,每个位数组实现为一个 Lua number。运算符以语法扩展和虚拟机指令(包括元方法)的形式提供。

RiscLua 描述

RiscLua,版本 6 之前的版本,使用十六进制字面量并具有位运算符,每个运算符都有一个对应的事件。

x&y                __bit_and
x|y                __bit_or
x^^y               __bit_xor
~x                 __bit_not
-- also has arithmetic shifts:
x<<y              __bit_lshift
x>>y              __bit_rshift

这作为 Lua 的一个补丁实现。内部,每个位数组实现为一个 Lua number。运算符以语法扩展和虚拟机指令(包括元方法)的形式提供。此补丁不是独立的,而是合并到 RiscLua 中。

hextype.patch 描述

| & ^^ << >> ~ \\ !=

这作为 Lua 的一个补丁实现。内部,每个位数组实现为一个新的原始值类型(type(x) == 'hex', LUA_THEX),不同于 'number'。此类型本身在内部是一个无符号整数。运算符以语法扩展和虚拟机指令(包括元方法)的形式提供。

LuaPowerPatches 中的枚举/位操作 描述

-- example
local a1= enum.new( 0x10, "I'm A" )
assert( tonumber(a1)==16 )
assert( tostring(a1)=="0x10" )
assert( tonumber(a1"not")==4294967279 )
assert( tostring(a1"not")=="0xffffffef" )
local c1= enum.new( 10 )   -- I'm None!
assert( c1[3] == 1 )  -- 10 == 0x1010: bit 3 _is_ set

这作为 Lua 的一个补丁实现。内部,每个位数组实现为一个新的原始值类型(type() 返回两个值:“enum”和枚举族名称)。枚举值具有重载的 []() 操作,用于在 Lua 端执行位操作。

恳请

上述实现对以下两个问题处理不同(或在某些情况下根本不处理):

其中一个实现假设 32 位整数,并提供有符号和无符号右移。

另一个使用 long longunsigned long long,并依赖 C 编译器为每种情况正确执行右移(对我来说,在 x86 上使用 gcc 时效果很好,但 C89 和 C99 没有规定有符号右移的执行方式;这是“实现定义的行为”。)

第三个似乎完全忽略了这个问题,给我们 C 编译器在 lua_Integer 上决定的任何结果。

请注意,在添加运算符时,Java 将 >> 运算符定义为使用符号扩展,将 >>> 运算符定义为使用零扩展。

它们似乎都没有提供一种可移植的方法将任意大小的位域转换为有符号数。

如果 bitfield 接受另一个可选的布尔参数来指示结果应符号扩展到 lua_Integer 的完整大小,那么这个 [补丁] 会很棒。

顺便说一句,一种无分支的符号扩展位域的方法(Henry S. Warren Jr.,CACM v20 n6 1977 年 6 月)是这样的:

sext = 1 << (len - 1); i = (i ^ sext) - sext;
假设 i 是右对齐的,并且位域左边的所有位都是零;在上面的补丁中就是这种情况,其中 sextp 是指示需要符号扩展的可选参数。
if (len < LI_BITS)
{ i &= LI_MASK(len);
  if (sextp) 
  { lua_Integer sext = 1 << (len - 1);
    i = (i ^ sext) - sext;
  }
}

目的

位操作至少有两个非常不同的原因:(1)对少量成员集合的操作,以及(2)操纵 Lua 程序外部定义的显式数据表示中的字段。引用的位运算符实现主要针对后者。对于前者,请参阅 LuaPowerPatches 中的 Asko 的枚举/位操作补丁。

示例

以下是使用位运算符的 Lua 代码示例(用例):

典型用途包括:

评论

对于一个旨在与 C/C++ 接口的语言来说,位运算符不是语法的一部分是很奇怪的。当然,它们可以实现为函数——但这很笨拙。参见 FeatureProposals

“如何执行位操作?”是 LuaFaq 中的一个问题。

注意:Lua 5.1 中添加了十六进制字面量:0xfe。

Java 有一个名为 EnumSet 的位向量抽象 [1]。类似的东西也可以在 Lua 中实现。


RecentChanges · preferences
编辑 · 历史
最后编辑于 2020 年 6 月 2 日上午 9:24 GMT (差异)