惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
U
Unit 42
V
Visual Studio Blog
D
DataBreaches.Net
F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss
GbyAI
GbyAI
博客园 - 叶小钗
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
MongoDB | Blog
MongoDB | Blog
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
D
Docker
G
Google Developers Blog
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
S
SegmentFault 最新的问题

ccagml

使用valgrind观察luajit进程内存 - ccagml 从生产环境报错学习protobuf编码规则 - ccagml 跟着vscode插件学设计模式-工厂模式 - ccagml 拨开迷雾,探寻深夜游戏集群启动失败真相 - ccagml 从技能状态图标显示错误到给 LuaJIT 报告bug - ccagml 游戏系统MySQl执行超时问题排查 - ccagml lua中pairs和ipairs都做了什么操作 - ccagml lua中#号是怎么计算字符串长度的 - ccagml lua中#号是怎么计算长度的 - ccagml
lua中tonumber做了什么 - ccagml
2022-04-02 · via ccagml

1. 一个常见的例子

    a = tonumber("2333")

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