位元操作子 |
|
從 5.2 版開始,Lua 附帶 [bit32] 函式庫,其中新增對位元操作的支援。之前版本的 Lua 沒有包含位元操作子,但 bit32 已回傳到 5.1 版。此外,也有相對應的 Lua 函式庫和一些 Lua 修補版本。
Lua 中的位元操作子實作
int32_t
和 int64_t
lua_Number
型別間都具有相容的語意。同時也定義了 LuaJIT 2 位元操作語意。一般被認為是 Lua 中位元作業的最佳實務。介面類似 bitlib,但較新且打算取代之 [2][3]。
Op「bit」的介面。bxor 實作類似於 Roberto 的方法。(DavidManura)
Op (第 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)
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 授權條款。
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
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 數字實作。上述的原始運算提供簡單的程式碼,可對數字中的位元進行測試/設定/清除。位元運算可以定義為這些函式的條款。
Bit (第 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 數位陣列實作。此套件也包括用於將數字轉換為 16 進位字串或將 16 進位字串轉換為數字的函式,以及用於將 UTF8 轉換為 UCS2 字串的「utf8」模組,和與 Nokia 電腦有關的「noki」模組。授權採用 MIT 授權條款。
Dec
Hex (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)
BinDec
Hex 是完全用 Lua 編寫的。內部而言,每組位元陣列都是以大端序形式的 Lua 字串實作。授權採用 BSD 授權條款。
Utils 說明BitUtils 提供一些完全用 Lua 實作的程式碼片段。通常來說,內部而言,每組位元陣列都是以 Lua 數字實作。
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 操作碼提供 (包括元方法)。
Lua 說明RiscLua 的 6 版以前版本,會使用 16 進位字面量並具有位元運算元,每個運算元都有相應的事件
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 中。
| & ^^ << >> ~ \\ !=
這是以 Lua 的補丁實作的。內部而言,每組位元陣列都是以新的原值類型實作 (type(x) == 'hex'
、LUA_THEX
),與「數字」不同。此類型在內部是無符號整數。運算元是視為語法延伸和 VM 操作碼提供 (包括元方法)。
-- 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」和 enum 類別名稱)。enum 值具有過載的 []
和 ()
運算,可對 Lua 端的位元執行位元運算。
以上實作在兩個問題上有不同的處理方式(部分情況下甚至完全沒處理)
有一個實作假設為 32 位元整數,並提供有符號和無符號右位移。
另一個實作使用 long long
和 unsigned long long
,並依賴於 C 編譯器在每個情況下正確執行右位移(剛好對我來說在使用 gcc 的 x86 上執行得很好,但 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 中的 Enum/bit 操作修補程式。
以下是利用位元運算子(用例)的 Lua 程式碼範例
常見用途包括
對於打算與 C/C++ 相介接的語言來說,奇妙的是位元運算子並非語法的一部分。當然,它們可以做為函式實作,但這很笨拙。請參閱 FeatureProposals。
「如何執行位元運算?」是一個 LuaFaq 問題。
註:hex 文字在 Lua 5.1 中新增:0xfe。
Java 對稱為 EnumSet
的位元向量有一種抽象法 [1]。可以在 Lua 上執行類似的事情。