🔬
OpenResty 最佳实践
  • 序
  • 入门篇
  • Lua 入门
    • Lua 简介
    • Lua 环境搭建
    • Lua 编辑器选择
    • 基础数据类型
    • 表达式
    • 控制结构
      • if/else
      • while
      • repeat
      • for
      • break,return 和 goto
    • Lua 函数
      • 函数的定义
      • 函数的参数
      • 函数返回值
      • 全动态函数调用
    • 模块
    • String 库
    • Table 库
    • 日期时间函数
    • 数学库函数
    • 文件操作
  • Lua 高阶
    • 元表
    • 面向对象编程
    • 局部变量
    • 判断数组大小
    • 非空判断
    • 正则表达式
    • 虚变量
    • 抵制使用 module() 定义模块
    • 调用代码前先定义函数
    • 点号与冒号操作符的区别
    • module 是邪恶的
    • FFI
    • 什么是 JIT
  • Nginx
    • Nginx 新手起步
    • location 匹配规则
    • 静态文件服务
    • 日志
    • 反向代理
    • 负载均衡
    • 陷阱和常见错误
  • OpenResty
    • 环境搭建
      • Windows 平台
      • CentOS 平台
      • Ubuntu 平台
      • Mac OS X 平台
    • Hello World
    • 与其他 location 配合
    • 获取 uri 参数
    • 获取请求 body
    • 输出响应体
    • 日志输出
    • 简单 API Server 框架
    • 使用 Nginx 内置绑定变量
    • 子查询
    • 不同阶段共享变量
    • 防止 SQL 注入
    • 如何发起新 HTTP 请求
    • 如何完成 bit 操作
      • 一,复习二进制补码
      • 二,复习位运算
      • 三,LuaJIT 和 Lua BitOp Api
      • 四,位运算算法实例
      • 五,Lua BitOp 的安装
  • LuaRestyRedisLibrary
    • 访问有授权验证的 Redis
    • select+set_keepalive 组合操作引起的数据读写错误
    • redis 接口的二次封装(简化建连、拆连等细节)
    • redis 接口的二次封装(发布订阅)
    • pipeline 压缩请求数量
    • script 压缩复杂请求
    • 动态生成的 lua-resty-redis 模块方法
  • LuaCjsonLibrary
    • json 解析的异常捕获
    • 稀疏数组
    • 空 table 编码为 array 还是 object
  • PostgresNginxModule
    • 调用方式简介
    • 不支持事务
    • 超时
    • 健康监测
    • SQL 注入
  • LuaNginxModule
    • 执行阶段概念
    • 正确的记录日志
    • 热装载代码
    • 阻塞操作
    • 缓存
    • sleep
    • 定时任务
    • 禁止某些终端访问
    • 请求返回后继续执行
    • 调试
    • 请求中断后的处理
    • 我的 lua 代码需要调优么
    • 变量的共享范围
    • 动态限速
    • shared.dict 非队列性质
    • 正确使用长链接
    • 如何引用第三方 resty 库
    • 典型应用场景
    • 怎样理解 cosocket
    • 如何安全启动唯一实例的 timer
    • 如何正确的解析域名
  • LuaRestyDNSLibrary
    • 使用动态 DNS 来完成 HTTP 请求
  • LuaRestyLock
    • 缓存失效风暴
  • OpenResty 与 SSL
    • HTTPS 时代
    • 动态加载证书和 OCSP stapling
    • TLS session resumption
  • 测试
    • 代码静态分析
    • 单元测试
    • 代码覆盖率
    • API 测试
    • 性能测试
    • 持续集成
    • 灰度发布
      • 分流引擎设计
      • 控制台开发
      • 向运维平台发展
  • Web 服务
    • API 的设计
    • 数据合法性检测
    • 协议无痛升级
    • 代码规范
    • 连接池
    • C10K 编程
    • TIME_WAIT 问题
    • 与 Docker 使用的网络瓶颈
  • 火焰图
    • 什么是火焰图
    • 什么时候使用
    • 如何安装火焰图生成工具
    • 如何定位问题
    • 拓展阅读
    • FAQ
Powered by GitBook
On this page
  • 1,LuaJIT 中的 bit 操作
  • 2,Lua BitOp API 简介
  • 2.1 定义快捷方式
  • 2.2 位操作函数的返回值
  • 2.3 位操作函数简介
Edit on GitHub
  1. OpenResty
  2. 如何完成 bit 操作

三,LuaJIT 和 Lua BitOp Api

Previous二,复习位运算Next四,位运算算法实例

Last updated 2 years ago

1,LuaJIT 中的 bit 操作

因为从 OpenResty 1.5.8.1 就默认使用 LuaJIT 作为内置组件,我们可以在 LuaJIT 网站介绍 的页面上看到下面的描述:

LuaJIT 提供了几个内置扩展模块:

Bit.* —— 位运算模块。 LuaJIT 支持 定义的所有位操作:

bit.tobit,  bit.tohex,  bit.bnot,    bit.band, bit.bor,  bit.bxor,
bit.lshift, bit.rshift, bit.arshift, bit.rol,  bit.ror,  bit.bswap。

这个模块是 LuaJIT 内置的——您不需要下载或安装 Lua BitOp。Lua BitOp 站点提供了所有 的完整文档。

在使用模块的任何功能之前,请确保用 require 加载该模块:

local bit = require("bit")

LuaJIT 会忽略已经安装的 Lua BitOp 模块。这样,您就可以在共享安装上同时使用 Lua 和 LuaJIT 的位操作。

2,Lua BitOp API 简介

2.1 定义快捷方式

将常用的模块函数缓存在本地变量中是一种常见的(但不是必须的)做法。这作为一种快捷方式,可以节省一些输入,还可以加快解析它们的速度(只有在调用数十万次时才有意义)。

-- 请将下面的三行代码放在使用位运算开始的位置(这是个好习惯)
local bnot = bit.bnot
local band, bor, bxor = bit.band, bit.bor, bit.bxor
local lshift, rshift, rol = bit.lshift, bit.rshift, bit.rol
-- 等等

-- 使用快捷方式的示例:
local function tr_i(a, b, c, d, x, s)
  return rol(bxor(c, bor(b, bnot(d))) + a + x, s) + b
end

请谨记,and、or 和 not 是 Lua 中的保留关键字。它们不能用于变量名或字面量字段名。这就是为什么将相应的位操作函数命名为 band、bor 和 bnot(以及为保持一致性的 bxor)的原因。

注意:一个常见的陷阱是使用 bit 作为局部临时变量的名称 —— 好吧,不要这样做!

2.2 位操作函数的返回值

2.3 位操作函数简介

  • (1) y = bit.tobit(x)

    print(0xffffffff)                --> 4294967295 (*)
    print(bit.tobit(0xffffffff))     --> -1
    print(bit.tobit(0xffffffff + 1)) --> 0
    print(bit.tobit(2^40 + 1234))    --> 1234
  • (2) y = bit.tohex(x [,n])

    将函数的第一个参数转换为十六进制字符串。

    • 十六进制数字显示的数目由可选的第二个参数的绝对值给出。

    • 介于 1 到 8 之间的正数会生成小写的十六进制数字。

    • 负数生成大写的十六进制数字。

    • 仅使用最低有效的 4 * |n| 位。

    • 默认值:生成 8 个小写的十六进制数字。

    print(bit.tohex(1))              --> 00000001
    print(bit.tohex(-1))             --> ffffffff
    print(bit.tohex(0xffffffff))     --> ffffffff
    print(bit.tohex(-1, -8))         --> FFFFFFFF
    print(bit.tohex(0x21, 4))        --> 0021
    print(bit.tohex(0x87654321, 4))  --> 4321
  • (3) y = bit.bnot(x) 按位 NOT

    返回其参数的 按位 NOT 的结果。

    print(bit.bnot(0))            --> -1
    printx(bit.bnot(0))           --> 0xffffffff
    print(bit.bnot(-1))           --> 0
    print(bit.bnot(0xffffffff))   --> 0
    printx(bit.bnot(0x12345678))  --> 0xedcba987
  • (4) y = bit.bor(x1 [,x2...]) 按位或

    返回其所有参数的 按位或 运算结果。允许使用两个以上的参数。

    print(bit.bor(1, 2, 4, 8))                --> 15
  • (5) y = bit.band(x1 [,x2...]) 按位与

    返回其所有参数的 按位与 运算结果。允许使用两个以上的参数。

    printx(bit.band(0x12345678, 0xff))        --> 0x00000078
  • (6) y = bit.bxor(x1 [,x2...]) 按位异或

    返回其所有参数的 按位异或 运算结果。允许使用两个以上的参数。

    printx(bit.bxor(0xa5a5f0f0, 0xaa55ff00))  --> 0x0ff00ff0
  • (7) y = bit.lshift(x, n) 按位逻辑左移

    返回其第一个参数 按位逻辑左移 的运算结果,移动的位数由第二个参数给出。

    -- 按位逻辑左移
    print(bit.lshift(1, 0))              --> 1
    print(bit.lshift(1, 8))              --> 256
    print(bit.lshift(1, 40))             --> 256
  • (8) y = bit.rshift(x, n) 按位逻辑右移

    返回其第一个参数 按位逻辑右移 的运算结果,移动的位数由第二个参数给出。

    -- 按位逻辑右移
    print(bit.rshift(256, 8))            --> 1
    print(bit.rshift(-256, 8))           --> 16777215    -- 符号位没有被保留

    以上两种 逻辑移位 (Logical shifts) 操作会将第一个参数视为 无符号 数,最小移位可以是 0 位。

  • (9) y = bit.arshift(x, n) 按位算术右移

    返回其第一个参数 按位算术右移 的运算结果,移动的位数由第二个参数给出。

    -- 按位算术右移(符号位会被保留)
    print(bit.arshift(256, 8))           --> 1
    print(bit.arshift(-256, 8))          --> -1
    
    -- 三种移位运算的十六进制表示形式
    printx(bit.lshift(0x87654321, 12))   --> 0x54321000
    printx(bit.rshift(0x87654321, 12))   --> 0x00087654
    printx(bit.arshift(0x87654321, 12))  --> 0xfff87654

    算术右移 (Arithmetic right-shift) 操作会将最高有效位视为符号位,并且会在移动过程中被复制保留下来。 仅使用移位计数的低 5 位(减小到 [0...31] 范围)。

  • (10) y = bit.rol(x, n) 按位向左旋转

    返回其第一个参数 按位向左旋转 的运算结果,旋转位数由第二个参数给出。 从一边移出的位元会从另一边移回来。

    printx(bit.rol(0x12345678, 12))   --> 0x45678123
  • (11) y = bit.ror(x, n) 按位向右旋转

    返回其第一个参数 按位向右旋转 的运算结果,旋转的位数由第二个参数给出。 从一边移出的位元会从另一边移回来。

    printx(bit.rol(0x12345678, 12))   --> 0x45678123
    printx(bit.ror(0x12345678, 12))   --> 0x67812345

    以上两种旋转操作都是只使用较低的 5 位旋转计数 (减少到范围 [0..31])。

  • (12) y = bit.bswap(x) 交换字节

    交换其参数的字节并返回它。这可用于将小端 32 位数字转换为大端 32 位数字,反之亦然。

    printx(bit.bswap(0x12345678)) --> 0x78563412
    printx(bit.bswap(0x78563412)) --> 0x12345678

请注意,所有位操作都返回 有符号 的 32 位数字( )。默认情况下,这些数字打印为有符号的十进制数字。

将一个数字归一化为位运算的数值范围并返回。通常不需要这个函数,因为所有的位运算都已经对其所有的输入参数进行了归一化处理。详情请查看 。

一,复习二进制补码
二,复习位运算
三,LuaJIT 和 Lua BitOp Api
四,位运算算法实例
五,Lua BitOp 的安装
扩展模块
Lua BitOp
Lua BitOp API 函数
原理
操作语义