1. 一个常见的例子
a = tonumber("2333")
因为tonumber是lua内置的一个函数,所以我们来看对应的函数
static int gafqBase_tonumber(gafq_State *L)
{
int base = gafqL_optint(L, 2, 10); // 获取第二个参数,进制 默认10 ,可以是2-36的值
if (base == 10)
{
gafqL_checkany(L, 1); // 检查第一个参数,不是空
if (gafq_isnumber(L, 1)) // 判断是否是数字
{
gafq_pushnumber(L, gafq_tonumber(L, 1)); // 转成数字
return 1;
}
}
else
{
const char *s1 = gafqL_checkstring(L, 1);
char *s2;
unsigned long n;
gafqL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
// 调用库函数strtoul
// C 库函数unsigned long int strtoul(const char *str, char **endptr, int base)函数根据给定的base将str中字符串的初始部分转换为unsigned long int 值,
// 该值必须介于 2 和36(含),或为特殊值 0。
n = strtoul(s1, &s2, base);
if (s1 != s2)
{
while (isspace((unsigned char)(*s2)))
s2++;// 去掉所有空格
if (*s2 == '\0')
{ // 是正确的值
gafq_pushnumber(L, (gafq_Number)n);
return 1;
}
}
}
gafq_pushnil(L);// 转换失败 放入nil
return 1;
}
gafq_isnumber做了什么
//判断整数
GAFQ_API int gafq_isnumber(gafq_State *L, int idx)
{
TValue n;
const TValue *o = idx_to_Tvalue(L, idx); // 取出对应要转换的值
return tonumber(o, &n);
}
跳过上面现在先看gafq_tonumber 做了什么
//转成数字
GAFQ_API gafq_Number gafq_tonumber(gafq_State *L, int idx)
{
TValue n;
const TValue *o = idx_to_Tvalue(L, idx);
if (tonumber(o, &n))
return nvalue(o);
else
return 0;
}
我们看到了gafq_isnumber和gafq_tonumber都做了同样的事
TValue n;
const TValue *o = idx_to_Tvalue(L, idx);
tonumber(o, &n)
tonumber是一个宏
#define tonumber(o, n) (ttype(o) == GAFQ_TNUMBER || (((o) = gafqV_tonumber(o, n)) != NULL))
那么我们来看 gafqV_tonumber 做了什么
gafqV_tonumber 先判断是不是已经是数字,如果是数字就不用转换了,如果是字符串则还要转换
const TValue *gafqV_tonumber(const TValue *obj, TValue *n)
{
gafq_Number num;
if (ttisnumber(obj))
return obj;
if (ttisstring(obj) && gafqO_str2d(svalue(obj), &num))
{
setnvalue(n, num);
return n;
}
else
return NULL;
}
我们来看gafqO_str2d做了什么
// 字符串转整数
int gafqO_str2d(const char *s, gafq_Number *result)
{
char *endptr;
*result = gafq_str2number(s, &endptr);
if (endptr == s)
return 0; // 转换失败
if (*endptr == 'x' || *endptr == 'X') // 可能是十六进制转十进制
*result = cast_num(strtoul(s, &endptr, 16));
if (*endptr == '\0')
return 1; // 转换成功
while (isspace(cast(unsigned char, *endptr))) // 去掉所有空格
endptr++;
if (*endptr != '\0')
return 0; // 去掉后续空格还是转换失败
return 1; // 转换成功
}
gafq_str2number又是什么呢?
他是一个c函数strtod 的宏
#define gafq_str2number(s, p) strtod((s), (p))
结论
tonumber会先检查第二个参数是不是10, 如果是10,他会检查第一个参数是不是数字,如果是数字,就会进行转化.
判断 是否是数字 和 转换成数字,做了相同的操作
转换的过程 会先调用库函数 strtod
根据 strtod 的执行结果判断, 如果有x 或者X会额外尝试转成成16进制
如果 strtod 的结果去掉空格还不是 \0 就会认为转换失败