位运算符

lua-users home
wiki

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

从 5.2 版本开始,Lua 附带了库 [bit32],它添加了对位运算的支持。Lua 的早期版本不包含位运算符,但 bit32 已被移植回 5.1 版本。或者,也有一些 Lua 库可以实现此功能,以及一些 Lua 的修补版本。

Lua 中位运算符的实现

Lua BitOp (版本 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 数字。上面的基本操作提供了简单的代码来测试/设置/清除数字中的位。位运算可以用这些函数来定义。

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 数字或一个 Lua 数字数组。此包还包括用于将数字转换为十六进制字符串或从十六进制字符串转换的函数,一个用于 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 数字。

位运算符 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 数字。运算符作为语法扩展和 VM 操作码提供(包括元方法)。

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 数字。运算符作为语法扩展和 VM 操作码提供(包括元方法)。该补丁不是独立的,而是被整合到 RiscLua 中。

hextype.patch 描述

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

这是作为 Lua 的补丁实现的。在内部,每个位数组都实现为一个新的基本值类型 (type(x) == 'hex', LUA_THEX),不同于 'number'。此类型本身在内部是一个无符号整数。运算符作为语法扩展和 VM 操作码提供(包括元方法)。

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 程序外部定义的数据的显式表示中的字段进行操作。引用的按位运算符实现主要针对后者。有关前者的实现,请参见 Asko 在 LuaPowerPatches 中的枚举/位运算补丁。

示例

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

典型用途包括

评论

对于一种旨在与 C/C++ 交互的语言来说,位运算符不属于语法的一部分很奇怪。当然,它们可以作为函数实现 - 但这很笨拙。请参阅 FeatureProposals

“如何执行位运算?”是一个 LuaFaq 问题。

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

Java 有一个位向量的抽象,称为 EnumSet [1]。Lua 上也可以做类似的事情。


最近更改 · 首选项
编辑 · 历史记录
上次编辑于 2020 年 6 月 2 日下午 3:24 GMT (差异)