如何让宏定义支持字符串、整数、布尔输入并解决C4047错误
解决Lua表读取宏的C4047类型不匹配错误
问题背景
需要实现一个能读取Lua表中字符串、整数、布尔类型元素的C宏,当前代码触发C4047错误:'char *' differs in levels of indirection from 'int'。
关联代码
Lua表定义(table.lua):
Strings = { Apply = {"successfully applied", true, 150, "OK" }, Check = {"check done", 100, false }, Test = {"test completed", "Fail", 1, true } };
原C语言宏及调用代码:
#define lua_get_test(L, tbl, ...) do { \ lua_getfield(L, lua_gettop(L), tbl); \ if (lua_istable(L, lua_gettop(L))) \ { \ int n = (int)lua_rawlen(L, lua_gettop(L)); \ for (int i = 1; i <= n; i++) { \ lua_rawgeti(L, lua_gettop(L), i); \ if (lua_isstring(L, lua_gettop(L))) \ strcpy(__VA_ARGS__, lua_tostring(L, lua_gettop(L))); \ else if(lua_isboolean(L, lua_gettop(L))) \ __VA_ARGS__ = lua_toboolean(L, lua_gettop(L)); \ else if(lua_isinteger(L, lua_gettop(L))) \ __VA_ARGS__ = (int)lua_tointeger(L, lua_gettop(L)); \ else \ continue; \ lua_pop(L, 1); \ } \ } \ lua_pop(L, 1); \ } while(false) void read_table(void) { lua_State *L; L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, "table.lua") || lua_pcall(L, 0, 0, 0)) { ShowError("Error reading 'table.lua'\n"); return; } lua_getglobal(L, "Strings"); lua_get_test(L, "Apply", var_string, var_bool, var_int, var_string); lua_get_test(L, "Check", var_string, var_int, var_bool); lua_get_test(L, "Test", var_string, var_string, var_int, var_bool); lua_close(L); printf("Read Table complete.\n"); }
错误原因
- 可变参数处理逻辑错误:原宏循环中直接对
__VA_ARGS__执行赋值操作,相当于同时给所有传入的变量执行同一操作(比如给int变量调用strcpy),导致类型不匹配。 - 缺乏类型匹配机制:宏无法自动识别每个变量的类型,强行统一处理必然触发类型转换错误。
解决方案
核心思路
- 用C11的
_Generic关键字实现类型匹配,根据目标变量类型自动选择对应的Lua读取逻辑。 - 拆分宏为对应参数个数的版本,确保每个变量对应Lua表中指定位置的元素,逐个处理避免批量赋值错误。
修正后的代码
#include <lua.h> #include <lauxlib.h> #include <lualib.h> #include <stdio.h> #include <stdbool.h> #include <string.h> void ShowError(const char* msg) { fprintf(stderr, "%s", msg); } // 辅助宏:根据目标变量类型读取单个Lua表元素 #define LUA_READ_ONE(L, idx, var) do { \ lua_rawgeti(L, -1, idx); \ _Generic((var), \ char*: strcpy(var, lua_tostring(L, -1)), \ int: (var = (int)lua_tointeger(L, -1)), \ bool: (var = lua_toboolean(L, -1)) \ ); \ lua_pop(L, 1); \ } while(false) // 读取含4个元素的Lua表 #define lua_read_4(L, tbl, v1, v2, v3, v4) do { \ lua_getfield(L, -1, tbl); \ if (lua_istable(L, -1)) { \ LUA_READ_ONE(L, 1, v1); \ LUA_READ_ONE(L, 2, v2); \ LUA_READ_ONE(L, 3, v3); \ LUA_READ_ONE(L, 4, v4); \ } \ lua_pop(L, 1); \ } while(false) // 读取含3个元素的Lua表 #define lua_read_3(L, tbl, v1, v2, v3) do { \ lua_getfield(L, -1, tbl); \ if (lua_istable(L, -1)) { \ LUA_READ_ONE(L, 1, v1); \ LUA_READ_ONE(L, 2, v2); \ LUA_READ_ONE(L, 3, v3); \ } \ lua_pop(L, 1); \ } while(false) void read_table(void) { lua_State *L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, "table.lua") || lua_pcall(L, 0, 0, 0)) { ShowError("Error reading 'table.lua'\n"); lua_close(L); return; } lua_getglobal(L, "Strings"); // 读取Apply表 char apply_str1[100], apply_str2[100]; bool apply_bool; int apply_int; lua_read_4(L, "Apply", apply_str1, apply_bool, apply_int, apply_str2); // 读取Check表 char check_str[100]; int check_int; bool check_bool; lua_read_3(L, "Check", check_str, check_int, check_bool); // 读取Test表 char test_str1[100], test_str2[100]; int test_int; bool test_bool; lua_read_4(L, "Test", test_str1, test_str2, test_int, test_bool); // 验证读取结果 printf("Apply: %s, %d, %d, %s\n", apply_str1, apply_bool, apply_int, apply_str2); printf("Check: %s, %d, %d\n", check_str, check_int, check_bool); printf("Test: %s, %s, %d, %d\n", test_str1, test_str2, test_int, test_bool); lua_close(L); printf("Read Table complete.\n"); } int main() { read_table(); return 0; }
说明
_Generic关键字会根据目标变量的类型,自动选择对应的赋值逻辑,确保类型匹配。- 针对不同元素个数的Lua表定义专用宏(
lua_read_3、lua_read_4),保证每个变量对应表中指定位置的元素,避免批量赋值的类型错误。 - 辅助宏
LUA_READ_ONE封装单个元素的读取逻辑,简化代码复用。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

