C函数luaB_tonumber是lua库函数tonumber的具体实现。luaB_tonumber的目的是将传入的参数转换为一个数字。luaB_tonumber的声明如下:
static int luaB_tonumber (lua_State *L);
luaB_tonumber接受两个参数e和base,由L的栈携带。
先看luaB_tonumber源码:
static int luaB_tonumber (lua_State *L) {
if (lua_isnoneornil(L, 2)) { /* standard conversion? */
luaL_checkany(L, 1);
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
lua_settop(L, 1); /* yes; return it */
return 1;
}
else {
size_t l;
const char *s = lua_tolstring(L, 1, &l);
if (s != NULL && lua_stringtonumber(L, s) == l + 1)
return 1; /* successful conversion to number */
/* else not a number */
}
}
else {
size_t l;
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
return 1;
} /* else not a number */
} /* else not a number */
lua_pushnil(L); /* not a number */
return 1;
}
luaB_tonumber首先执行代码if (lua_isnoneornil(L, 2))
判断是否传入了转换的基数base,如果不传入参数base,则是标准转换,即将参数转换成十进制:
luaL_checkany(L, 1);
检查第一个参数e是否存在;if (lua_type(L, 1) == LUA_TNUMBER)
判断参数e是否已经是数字,如果是就直接将其入栈,函数执行完毕,否则继续执行;const char *s = lua_tolstring(L, 1, &l);
尝试将参数e转换成字符串;然后执行if (s != NULL && lua_stringtonumber(L, s) == l + 1)
判断是否转换成功,如果成功,函数执行完毕。不是标准转换:
lua_Integer base = luaL_checkinteger(L, 2);
获取base;luaL_checktype(L, 1, LUA_TSTRING);
进行检查:如果参数e不是数字,则只能是字符串;luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
,这里对传入的base做了一次检查,转换的基数只能是\[2,36\]内的整数;if (b_str2int(s, (int)base, &n) == s + l)
尝试将字符串s转换成以base为基数的数字;其中b_str2int就是lbaselib.c中的一个内部方法;如果转换成功就将结果入站。最后,如果无法转换,luaB_tonumber调用lua_pushnil(L);
将nil入站,表示无法转换成数字。