前言

作为C语言基础,在面试的时候,经常会被要求实现数值到字符串、或者字符串到数值的转换函数。虽然难度不大,但是很容易在一些细节上出现纰漏。刚好最近在深度分析Redis7.0源代码。闲暇之余,顺带把这部分代码摘录出来,进行分析、注解。
作为一个学习记录的同时也方便后来者快速了解Redis内部是如何实现的。日后面试也许能用的上。

Redis实现方式

代码片段注释


int string2ll(const char *s, size_t slen, long long *value) {
    const char *p = s; //指向s开始位置
    size_t plen = 0;   //
    int negative = 0;  //负数
    unsigned long long v;

    /* 如果传递表示字符串长度参数为0,则无需转换,直接返回 0 */
    if (plen == slen)
        return 0;

    /* 特殊情况, 只有一个字符,并且是0字母 */
    if (slen == 1 && p[0] == '0') {
        if (value != NULL) *value = 0;
        return 1;
    }

    /* 字符串可能是表示带符号的整数,那么需要先处理符号。 */
    /* 处理负数:仅仅是设置负号,然后就类似正数的处理方式进行处理 . 完毕后转换成负数 */
    if (p[0] == '-') {
        negative = 1;
        p++; plen++;

        /* 只有负号,即字符串是这样:"-", 这种字符串直接,异常退出 */
        if (plen == slen)
            return 0;
    }

    /* 第一个字符必须是1-9,否则字符串应该是0 */
    if (p[0] >= '1' && p[0] <= '9') {
        v = p[0]-'0';//转成整数
        p++; plen++;
    } else {
        return 0;
    }

    /* 分析剩下的所有字符,并且每一个步都检查是否溢出。
       如果遇到非字符,则循环退出:p[0] <'0' || p[0] > '9'
       字符串分析完毕,则循环退出:plen >= slen  */
    while (plen < slen && p[0] >= '0' && p[0] <= '9') {
        if (v > (ULLONG_MAX / 10)) /* 先判断溢出,在累加。如果计算后再判断,这时候已经溢出掉了. */
            return 0;
        v *= 10;

        if (v > (ULLONG_MAX - (p[0]-'0'))) /* 道理同上,这里我们可以借鉴:判断溢出的方式. */
            return 0;
        v += p[0]-'0';

        p++; plen++;
    }

    /* 还有字符没有处理完,到这里其实就是上面的while循环条件, p[0]不是0-9的数字 */
    if (plen < slen)
        return 0;

    /* 转换为负数,并且要检查溢出 */
    /* 整个转换都是使用unsigned long long 作为临时值,最后保存的结果是有符号的,需要转换为
     * long long  ,这样在赋值和负数转变时候需要做溢出判断。
     */
    if (negative) {
        if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* 溢出检查 */
            return 0;
        if (value != NULL) *value = -v;
    } else {
        if (v > LLONG_MAX) /* 溢出检查. */
            return 0;
        if (value != NULL) *value = v;
    }
    return 1;
}

代码逻辑分析小结

string2ll整体思路是:处理符号,然后逐个字符进行转换,从第一个字符开始转换,每一次转换都判断本次转换后的结果是否溢出,如果溢出就返回转换失败,否则就转换成功,继续遍历下一个字符。

疑问&思考

这个函数在Redis内部作为工具函数,用的挺好的,但是如果用来应付找工作面试,估计是不合格的了。
为什么?您知道么?

这里就不妨提出几个问题,抛砖引玉:
1,指针参数,一定是有效的么?
2,字符串带空格怎么办?这个函数直接是转换失败,但是如果允许前后带空格呢?怎么修改?
3,是否存在优化空间?第一个字符需要单独判断么?能否一个循环直接解决?
还有么? 留给读者自己思考下 ^_^ 。


哈逗
9 声望0 粉丝

擅长后端架构的一枚普普通通程序员