辅助缓冲区(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;
}