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

辅助缓冲区(luaL_Buffer)

当需要在 C 代码中逐步构建一个长字符串时,反复使用 lua_pushstring + lua_concat 效率很低。Lua 辅助库提供了专门的 Buffer 机制。

基本用法

luaL_Buffer b;
luaL_buffinit(L, &b);              // 初始化 
luaL_addstring(&b, "Hello");       // 追加 
luaL_addchar(&b, ' ');
luaL_addstring(&b, "Lua");
luaL_pushresult(&b);               // 将结果压入栈 

Buffer 内部使用一块局部数组作为初始空间,超出后自动通过 Lua 分配器扩展。

常用 API

函数/宏说明
luaL_buffinit(L, B)初始化 Buffer
luaL_prepbuffsize(B, sz)确保剩余空间 ≥ sz,返回可写入的 char*
luaL_prepbuffer(B)同上,使用默认大小 LUAL_BUFFERSIZE
luaL_addchar(B, c)追加单个字符
luaL_addstring(B, s)追加 C 字符串
luaL_addlstring(B, s, l)追加指定长度的字符串
luaL_addvalue(B)将栈顶值弹出并追加到 buffer
luaL_pushresult(B)完成,将最终字符串压入栈
luaL_pushresultsize(B, sz)完成并指定结果大小
luaL_buffinitsize(L, B, sz)初始化并预分配 sz 空间
luaL_bufflen(B)当前已写入长度
luaL_buffaddr(B)当前缓冲区的 char* 地址

高级用法:直接写入缓冲区

luaL_Buffer b;
char *p = luaL_prepbuffsize(&b, 256);
// 直接向 p 写入最多 256 字节 
size_t written = sprintf(p, "value=%d", 42);
luaL_addsize(&b, written);   // 通知 buffer 实际写入量 
luaL_pushresult(&b);

将栈值追加到 buffer

luaL_addvalue 非常有用,可以将 Lua 值(如 tostring 后的数字)追加:

luaL_Buffer b;
luaL_buffinit(L, &b);
lua_pushinteger(L, 42);
luaL_tolstring(L, -1, NULL);   // 转换为 string 压栈 
luaL_addvalue(&b);             // 弹出并追加 
luaL_pushresult(&b);

注意:luaL_addvalue弹出栈顶值。

完整代码


#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);

    luaL_Buffer b;
    luaL_buffinit(L, &b);
    luaL_addstring(&b, "Hello");
    luaL_addchar(&b, ' ');
    luaL_addstring(&b, "World");
    luaL_pushresult(&b);
    assert(strcmp(lua_tostring(L, -1), "Hello World") == 0);
    lua_pop(L, 1);

    luaL_buffinit(L, &b);
    for (int i = 1; i <= 5; i++) {
        char *p = luaL_prepbuffsize(&b, 32);
        int n = snprintf(p, 32, "[%d] ", i);
        luaL_addsize(&b, (size_t)n);
    }
    luaL_pushresult(&b);
    assert(strcmp(lua_tostring(L, -1), "[1] [2] [3] [4] [5] ") == 0);
    lua_pop(L, 1);

    luaL_buffinit(L, &b);
    luaL_addstring(&b, "values: ");
    for (int i = 1; i <= 3; i++) {
        lua_pushinteger(L, i * 10);
        luaL_tolstring(L, -1, NULL);
        luaL_addvalue(&b);
        if (i < 3)
            luaL_addstring(&b, ", ");
    }
    luaL_pushresult(&b);
    assert(strcmp(lua_tostring(L, -1), "values: 10, 20, 30") == 0);
    lua_pop(L, 1);

    luaL_buffinit(L, &b);
    for (int i = 0; i < 1000; i++) {
        luaL_addstring(&b, "x");
    }
    luaL_pushresult(&b);
    size_t len;
    lua_tolstring(L, -1, &len);
    assert(len == 1000);
    lua_pop(L, 1);

    lua_close(L);
    puts("16-buffer: ok");
    return 0;
}