算术、比较与字符串操作
Lua C API 提供了直接在栈上执行算术运算、比较和字符串操作的函数,无需在 Lua 代码中完成。
栈上算术运算
void lua_arith(lua_State *L, int op);
操作数必须从栈顶弹出:
- 一元运算(
UNM、BNOT):弹出 1 个,压入结果 - 二元运算(
ADD、SUB等):弹出 2 个,压入结果
支持的操作码:
| 宏 | 含义 |
|---|---|
LUA_OPADD | 加法 + |
LUA_OPSUB | 减法 - |
LUA_OPMUL | 乘法 * |
LUA_OPMOD | 取模 % |
LUA_OPPOW | 幂 ^ |
LUA_OPDIV | 除法 / |
LUA_OPIDIV | 整除 // |
LUA_OPBAND | 按位与 & |
LUA_OPBOR | 按位或 | |
LUA_OPBXOR | 按位异或 ~ |
LUA_OPSHL | 左移 << |
LUA_OPSHR | 右移 >> |
LUA_OPUNM | 取负 - |
LUA_OPBNOT | 按位非 ~ |
操作数类型必须兼容(整数或浮点),否则会触发错误。在
pcall保护外使用需谨慎。
比较
int lua_compare(lua_State *L, int idx1, int idx2, int op);
int lua_rawequal(lua_State *L, int idx1, int idx2);
| 宏 | 含义 |
|---|---|
LUA_OPEQ | 等于 == |
LUA_OPLT | 小于 < |
LUA_OPLE | 小于等于 <= |
lua_compare触发元方法(__eq、__lt、__le)lua_rawequal不触发元方法,直接比较原始值
返回值:1 表示比较成立,0 表示不成立。
连接
void lua_concat(lua_State *L, int n);
将栈顶 n 个值弹出,连接成一个字符串压回栈顶。如果值是 number,会自动转换为 string。会触发 __concat 元方法。
长度
void lua_len(lua_State *L, int idx);
将 #idx 的结果压入栈顶。对 table 会触发 __len 元方法。对 string 返回字节长度。
字符串转数字
size_t lua_stringtonumber(lua_State *L, const char *s);
将字符串 s 转换为 number/integer 并压入栈。返回转换消耗的字节数(0 表示失败)。
辅助库字符串函数
luaL_tolstring
const char *luaL_tolstring(lua_State *L, int idx, size_t *len);
调用 tostring(idx),将结果压入栈顶并返回字符串指针。与 lua_tolstring 不同,它会触发 __tostring 元方法。
luaL_gsub
const char *luaL_gsub(lua_State *L, const char *s,
const char *p, const char *r);
将字符串 s 中的所有 p 替换为 r,结果压入栈顶并返回指针。
完整代码
#include <assert.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <stdio.h>
#include <string.h>
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushinteger(L, 10);
lua_pushinteger(L, 3);
lua_arith(L, LUA_OPADD);
assert(lua_tointeger(L, -1) == 13);
lua_pop(L, 1);
lua_pushinteger(L, 10);
lua_pushinteger(L, 3);
lua_arith(L, LUA_OPIDIV);
assert(lua_tointeger(L, -1) == 3);
lua_pop(L, 1);
lua_pushinteger(L, 7);
lua_arith(L, LUA_OPBNOT);
assert(lua_tointeger(L, -1) == -8);
lua_pop(L, 1);
lua_pushinteger(L, 5);
lua_pushinteger(L, 10);
assert(lua_compare(L, -2, -1, LUA_OPLT) == 1);
assert(lua_rawequal(L, -2, -1) == 0);
lua_pop(L, 2);
lua_pushstring(L, "Hello");
lua_pushstring(L, " ");
lua_pushstring(L, "Lua");
lua_concat(L, 3);
assert(strcmp(lua_tostring(L, -1), "Hello Lua") == 0);
lua_pop(L, 1);
lua_pushinteger(L, 42);
lua_pushstring(L, " apples");
lua_concat(L, 2);
assert(strcmp(lua_tostring(L, -1), "42 apples") == 0);
lua_pop(L, 1);
lua_pushstring(L, "hello");
lua_len(L, -1);
assert(lua_tointeger(L, -1) == 5);
lua_pop(L, 2);
lua_newtable(L);
lua_pushinteger(L, 1);
lua_seti(L, -2, 1);
lua_pushinteger(L, 2);
lua_seti(L, -2, 2);
lua_pushinteger(L, 3);
lua_seti(L, -2, 3);
lua_len(L, -1);
assert(lua_tointeger(L, -1) == 3);
lua_pop(L, 2);
size_t n = lua_stringtonumber(L, "3.14159");
assert(n == 8);
assert(lua_tonumber(L, -1) == 3.14159);
lua_pop(L, 1);
n = lua_stringtonumber(L, "not a number");
assert(n == 0);
lua_pushinteger(L, 12345);
size_t len;
const char *s = luaL_tolstring(L, -1, &len);
assert(strcmp(s, "12345") == 0);
assert(len == 5);
lua_pop(L, 2);
s = luaL_gsub(L, "hello world", "world", "lua");
assert(strcmp(s, "hello lua") == 0);
lua_pop(L, 1);
lua_close(L);
puts("13-arith: ok");
return 0;
}