Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

算术、比较与字符串操作

Lua C API 提供了直接在栈上执行算术运算、比较和字符串操作的函数,无需在 Lua 代码中完成。

栈上算术运算

void lua_arith(lua_State *L, int op);

操作数必须从栈顶弹出:

  • 一元运算(UNMBNOT):弹出 1 个,压入结果
  • 二元运算(ADDSUB 等):弹出 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;
}