yanbin's Blog
Lua 调用的 C 函数保存 state 的两种方式: Storing State in C Functions 笔记
/* variable with a unique address */ static char key = 'k'; /* store a string */ lua_pushlightuserdata(L, (void *)key); /* push address */ lua_pushstring(L, myStr); /* push value */ lua_settable(L, LUA_REGISTRYINDEX); /* registry[&kye] = myStr */ /* retrieve a string */ lua_pushlightuserdata(L, (void *)key); /* push address */ lua_gettable(L, LUA_REGISTRYINDEX); /* retrieve value */ const char *myStr = lua_tostring(L, -1); /* convert to C string */
/* variable with a unique address */ static char key = 'k'; /* store a string */ lua_pushstring(L, myStr); lua_rawsetp(L, LUA_REGISTRYINDEX, (void *)&key); /* retrieve a string */ lua_rawgetp(L, LUA_REGISTRYINDEX, (void *)&key); const char *myStr = lua_tostring(L, -1);
以上这些创建 key 以访问 table 规则对普通 table 也适用。
static int counter(lua_State *L);
int newCounter(lua_State *L)
{
lua_pushinteger(L, 0);
/* 使用 counter 作为 base function 创建 C closure, 讲 stack TOP N 作为 upvalues */
lua_pushcclosure(L, &counter, 1);
return 1;
}
static int counter(lua_State *L)
{
int val = lua_tointeger(L, lua_upvalueindex(1));
lua_pushinteger(L, ++val);
lua_pushvalue(L, -1); /* duplicate new vlaue */
lua_replace(L, lua_upvalueindex(1));
return 1;
}
#define luaL_newlib(L, lib) \
(luaL_newlibtable(L, lib), luaL_setfuncs(L, lib, 0))
关键点是 luaL_setfuncs() 这个函数讲 statck top N 个 value 作为 upvalues 指定给 library 中的函数。
luaL_newlib() 定义中这个 N 是 0, 这个函数是用不成了。不过可以用如下方式:
/* create library table */
luaL_newlibtable(L, lib);
/* create shared value */
lua_newtable(L);
/* add functions in list 'lib' to the new library,
* sharing previous table as upvalue
*/
luaL_setfuncs(L, lib, 1);
参考:
Programming in Lua third edition 28.3
为什么使用 do {} while(0)
有些宏定义含有多行代码,一般使用 do {} while(0) 把代码放在 'do' 和 'while' 之间的 '{}' 中。
#define foorbar(msg, callback) do {\
struct Task __task = msg_to_task((msg)); \
if (__task != NULL) { \
process(__task, (callback)); \
char *__msg = task_to_msg(__task); \
if (__msg != NULL) \ {
send_msg(__msg); \
free(__msg); \
} \
destroy_task(__task); \
} while (0)
这样用的原因是:
1.符合 C/C++ 语法习惯。
每条语句后面都一个';', 而 do {} while 语句后面也要加一个 ';'.
2.避免出现语法错误。
不用 do {} while(0) 把多行代码包起来,在 if else 语句中就会有语法错误,例如:
#define foorbar(a, b) foor((a)); bar((b)) if (something) /* 以下有语法错误 */ foorbar(3, 2); else // do something
仅仅使用 '{}' 把多行代码包起来,如果在调用宏之后加 ';', 也会有语法错误。
#define foorbar(a, b) {\
foor((a)); bar((b));\
}
foorbar(3, 2); // 此处有语法错误
/* 编译器提示:
* error: expected ‘;’ before ‘}’ token
* 如果不加 ';', 不会有语法错误但是这样不符合 C/C++ 的语法习惯
*/
3.do {} while(0) 可以根据条件跳出执行。
#define foorbar() do {\
struct condition __cond; \
if (__cond.wait_cond()) \
break; // 条件发生退出执行 \
// 条件没有发生 do something
} while(0)
4.私以为 do {} while(0) 可以保证代码执行并且只执行一次。
5.需要注意的地方。
(a)宏定义时用 '\' 连接多行语句;
(b)宏定义中定义变量,注意与外部变量名字冲突,不然原本希望用外面的变量,却用了新定义的变量。
(c)有些编译器会优化掉 do {} while(0); 直接展开 '{}' 内的代码, 如(b)所描述,此时会出现语法错误。
FIXME: 如果内部有 'break' 并且 'break' 的执行依赖运行时条件,编译器就不会优化掉 do {} while(0); 了。
举例:
#define foorbar() do {\
struct condition cond; \
if (cond.wait_cond()) \
break; // 条件发生退出执行 \
// 条件没有发生 do something
} while(0)
struct condition cond;
// do something
foobar(); // 到底用的是哪一个 cond?
#define foorbar(a, b) do {\
const char *something = get_something(a, b); \
} while(0)
const char *something;
// do something
foorbar(3, 9); // 如果编译器优化掉了 do {} while(0); 这里有语法错误。
感谢 老猫,mike2,MovableType@源赖朝 三位网友。
参考:
do { … } while (0) — what is it good for?
do{}while(0) 的作用
