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 就会认为转换失败

发表评论