目录
一. 位运算
与算术运算符不同,位运算符只能用于整型数。位运算符包括 &(按位与)、|(按位或)、~(按位异或)、>>(逻辑右移)、(逻辑左移) 和 一元运算符~(按位取反) 。(注意:在其他一些语言中,异或运算符位^, 而在Lua语言中^ 代表幂运算)
-- 下面例子都是用16进制表现
string.format("%x", 0xff & 0xabcd) --> cd
string.format("%x", 0xff | 0xabcd) --> abff
string.format("%x", 0xaaaa ~ -1) --> ffffffffffff5555
string.format("%x", ~0) --> ffffffffffffffff
两个移位操作都会用0填充空出的位,这个行为通常称为逻辑移位。Lua语言没有提供算术右移,即 使用符合位填充空出的位。我们可以通过向下取整除法(floor除法),除以合适的2的整数次幂来实现算术右移(例如,x//16与算术右移4位等价)
移位数是负数表示向相反的方向移位,即a>>n 与 a:
string.format("%x",0xff << 12) -->ff000
string.format("%x", 0xff >> -12) --> abff
如果移位数等于或大于整型表示的位数(标准Lua为64位,精简Lua为32位),由于所有的位都被结果中移出了,所以结果是0:
string.format("%x", -1 << 80) --> 0
二. 无符号整型数(简单的说 不带正负号的整型数)
2.1 整型类型的定义
整型有无符号(unsigned)和 有符号(signed)两种类型。在默认情况下声明的整型变量都是有符号的类型。
无符号整型和有符号整型的区别:无符号类型可以存放的正数范围比有符号整型中范围大一倍,因为有符号类型将最高位用来存储符号,而无符号类型全部存储数字
2.2 Lua中的无符号整型
2.2.3 如何处理无符号整型数,请看下面例子
> x = 13835058055282163712 --这是一个比2^63-1 还大的数,所以X是一个无符号整型数
> x --> - 4611686018427387904
-- 在控制台输出为 一个负数,因为Lua整型默认是有符号整型, 正数部分最大是 2^63-1 ,
-- 所以X 比 2^63-1 还大 4611686018427387904 这么多,所以自动转换成负数
那么如果需要对有符号整数进行处理的话,需要怎么做呢?
a. 可以使用选项 %u 或 %x 在函数string.format 中指定以无符号整型数进行输出
string.format("%u", x) --> 13835058055282163712
sting.format("0x%X", x) --> 0xC000000000000000 (十六进制)
b. 加法、减法和乘法操作对于有符号整型数和无符号整型数是一样的
string.format("%u", x) --> 13835058055282163712
string.format("%u", x + 1) --> 13835058055282163713
string.format("%u", x - 1) --> 13835058055282163711
c. 比较运算符 比较 不同符号位的整型数会出现问题,因为有符号整型的整数更小,代表的是负数,
0x7fffffffffffffff < 0x8000000000000000 --> false
Lua5.3提供了函数math.ult 来比较无符号整型数
math.ult(0x7fffffffffffffff, 0x8000000000000000) --> true
或者 在进行有符号比较前先用掩码掩去两个操作数的符号位
mask = 0x8000000000000000
(0x77fffffffffffffff ~ mask) < (0x8000000000000000 ~ mask) --> true
d. 无符号除法(算法直接用)
function udiv(n, d)
if d < 0 then
if math.ult(n, d) then
return 0
else
return 1
end
local q = ((n >> 1) // d) << 1
local r = n - q * d
if not math.utl(r, d) then q = q + 1 end
return q
end
end
e. 无符号整型数转换为浮点型数(算法直接用)
要把一个无符号整型数转换位浮点型数,可以先将其转换成有符号整型数,取模纠正结果
u = 11529215046068469760
f = (u + 0.0) % 2^64
string.format("%.0f"", f) --> 11529215046068469760
f. 浮点型数转换为无符号整型数(算法直接用)
f = 0xA000000000000000.0
u = math.tointeger(((f + 2 ^63) % 2^64) - 2^63)
string.format("%x", u) --> a000000000000000
三. 打包和解包二进制数据
函数 string.pack: 会把值 "打包"为二进制字符串
函数 string.unpack: 则从字符串中提取这些值
string.pack 和 string.unpack 的第一个参数是格式化字符串,用于描述如何打包数据。格式化字符串中的每个字母都描述了如何打包/解包一个值
s = string.pack("iii", 3, -27, 450)
> #s --> 12
> string.unpack("iii",s) -->3 -27 450 13(即 unpack函数会返回最后一个读取的元素在字符串的位置)
string.unpack 有一个可选的第三参数,用于指定开始读取的位置
例1. 输出一个指定字符串中所有被打包的字符串
s = "hello\0Lua\0world\0"
local i = 1
while i <= #s do
local res
res, i = string.unpack("z", s, i)
print(res)
end
--> hello
--> Lua
--> world
选项 z意味着一个以\0结尾的字符串