• 字符数字转换 atoi 与 strtol


    原文:http://www.cnblogs.com/JefferyZhou/archive/2010/07/01/1769555.html

    在很多时候我们都很清楚 atoX 系列函数: atoi , atol , atof
    新来的一系列函数:  strtol,  strtoul, strtod 
    通常有如下的关系:
    1. 对应关系其中: 

              atoi   (把字符串转到整形)    --对应--   strtol  (把字符串转到长整形)           

              atol   (把字符串转到长整形)    --对应--   strtol  (把字符串转到长整形)           

              atof   (把字符串转到浮点数)    --对应--   strtod (把字符串转到浮点数) 
    2. atoX 系列是 三十年前的函数 strtoX 系列是后十年产品


    3. atoX 系列接口,没有成功失败的区别(标准实现中),    strtoX 系列接口,有成功失败的区别


        比如:int i_atoi_lfs =  atoi(""); 与 int i_atoi_rfs = atoi("0"); 两个得到的是一样的,没有任何区别         

         而: int i_atoi_lfs =  strtol  ("", NULL,10); 与 int i_atoi_rfs = strtol  ("0", NULL,10);  得到的结果都是0,但是左边会置失败标志位。


    4. msvcr80.dll  的具体实现:

    1
    2
    3
    4
    5
    int __cdecl atoi(__in_z const char *_Str){  return _tstoi(_Str);  }   
    int __cdecl _tstoi(     const _TCHAR *nptr        ){    return (int)_tstol(nptr);}
    int __cdecl _tstoi(     const _TCHAR *nptr        ){    return (int)_tstol(nptr);}
    long __cdecl _tstol(const _TCHAR *nptr){return _tcstol(nptr, NULL, 10);}
    #define _tcstol   strtol
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <pre class="brush:cpp">extern "C" long __cdecl strtol (
            const char *nptr,
            char **endptr,
            int ibase
            )
    {
        if (__locale_changed == 0)
        {
            return (long) strtoxl(&__initiallocalestructinfo, nptr, (const char **)endptr, ibase, 0);
        }
        else
        {
            return (long) strtoxl(NULL, nptr, (const char **)endptr, ibase, 0);
        }
    }
    </pre>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    static unsigned long __cdecl strtoxl (
            _locale_t plocinfo,
            const char *nptr,
            const char **endptr,
            int ibase,
            int flags
            )
    {
            const char *p;
            char c;
            unsigned long number;
            unsigned digval;
            unsigned long maxval;
            _LocaleUpdate _loc_update(plocinfo);
     
            /* validation section */
            if (endptr != NULL)
            {
                /* store beginning of string in endptr */
                *endptr = (char *)nptr;
            }
            _VALIDATE_RETURN(nptr != NULL, EINVAL, 0L);
            _VALIDATE_RETURN(ibase == 0 || (2 <= ibase && ibase <= 36), EINVAL, 0L);
     
            p = nptr;                       /* p is our scanning pointer */
            number = 0;                     /* start with zero */
    //1. 这里关注到,函数没有检查传入的原字符指针是否为空, 如果传递了一个空的就崩了....
            c = *p++;                       /* read char */
            while ( _isspace_l((int)(unsigned char)c, _loc_update.GetLocaleT()) )
                c = *p++;               /* skip whitespace */
     
    //2. 不要期望能够 转换负负得正的字符串, 注意 "--100" 得到 0 ,  "-100" 得到 -100
            if (c == '-') {
                flags |= FL_NEG;        /* remember minus sign */
                c = *p++;
            }
            else if (c == '+')
                c = *p++;               /* skip sign */
    //3.  基数是 2 到 36 的闭区间 , [2, 36]
            if (ibase < 0 || ibase == 1 || ibase > 36) {
                /* bad base! */
                if (endptr)
                    /* store beginning of string in endptr */
                    *endptr = nptr;
                return 0L;              /* return 0 */
            }
     
    //4. 如果转换的时候基数输入是0, 则基数取决于原字符的前面两个字符,
    // 以非0开头的是 10进制字符串,
    // 以0x或者0X开头的是 16进制字符串,
    // 而仅仅以 0开头的是 8进制
            else if (ibase == 0) {
                /* determine base free-lance, based on first two chars of
                   string */
                if (c != '0')
                    ibase = 10;
                else if (*p == 'x' || *p == 'X')
                    ibase = 16;
                else
                    ibase = 8;
            }
     
    //  {{{   源码里面,这个地方 有这么一段 暂时不知道是干嘛的, 在我看来貌似是多余的
            if (ibase == 0) {
                /* determine base free-lance, based on first two chars of
                   string */
                if (c != '0')
                    ibase = 10;
                else if (*p == 'x' || *p == 'X')
                    ibase = 16;
                else
                    ibase = 8;
            }
    //}}}
     
    // 5. 如果是 16 进制,则跳过0x 或者 0X 的前缀
            if (ibase == 16) {
                /* we might have 0x in front of number; remove if there */
                if (c == '0' && (*p == 'x' || *p == 'X')) {
                    ++p;
                    c = *p++;       /* advance past prefix */
                }
            }
     
    // 6. 下面就是读取字符串,然后按照 local 解析应用的数值, 如果在转换过程中出现各种情况都会对标志位flags 进行标记
            /* if our number exceeds this, we will overflow on multiply */
            maxval = ULONG_MAX / ibase;
     
     
            for (;;) {      /* exit in middle of loop */
                /* convert c to value */
                if ( __ascii_isdigit_l((int)(unsigned char)c, _loc_update.GetLocaleT()) )
                    digval = c - '0';
                else if ( __ascii_isalpha_l((int)(unsigned char)c, _loc_update.GetLocaleT()) )
                    digval = __ascii_toupper(c) - 'A' + 10;
                else
                    break;
                if (digval >= (unsigned)ibase)
                    break;          /* exit loop if bad digit found */
     
                /* record the fact we have read one digit */
                flags |= FL_READDIGIT;
     
                /* we now need to compute number = number * base + digval,
                   but we need to know if overflow occured.  This requires
                   a tricky pre-check. */
     
                if (number < maxval || (number == maxval &&
                            (unsigned long)digval <= ULONG_MAX % ibase)) {
                    /* we won't overflow, go ahead and multiply */
                    number = number * ibase + digval;
                }
                else {
                    /* we would have overflowed -- set the overflow flag */
                    flags |= FL_OVERFLOW;
                    if (endptr == NULL) {
                        /* no need to keep on parsing if we
                           don't have to return the endptr. */
                        break;
                    }
                }
     
                c = *p++;               /* read next digit */
            }
     
            --p;                            /* point to place that stopped scan */
     
            if (!(flags & FL_READDIGIT)) {
                /* no number there; return 0 and point to beginning of
                   string */
                if (endptr)
                    /* store beginning of string in endptr later on */
                    p = nptr;
                number = 0L;            /* return 0 */
            }
            else if ( (flags & FL_OVERFLOW) ||
                    ( !(flags & FL_UNSIGNED) &&
                      ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
                        ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
            {
                /* overflow or signed overflow occurred */
                errno = ERANGE;                  //(老的实现方式和新的实现方式区别主要在这里, 新版友记录转换过程)
                if ( flags & FL_UNSIGNED )
                    number = ULONG_MAX;
                else if ( flags & FL_NEG )
                    number = (unsigned long)(-LONG_MIN);
                else
                    number = LONG_MAX;
            }
     
            if (endptr != NULL)
                /* store pointer to char that stopped the scan */
                *endptr = p;
     
            if (flags & FL_NEG)
                /* negate result if there was a neg sign */
                number = (unsigned long)(-(long)number);
     
            return number;                  /* done. */
    }

    所以 atoi 已经等同于strtol 

    Sign,  Clown , 2010.07.01 . 23:32 . HDPY

    [本文原创,转载请注明出处,在文章末尾提供原文链接http://www.cnblogs.com/JefferyZhou/,否则一旦发现,将按字节每人民币收费,绝不论价]

  • 相关阅读:
    mysql 15道语句练习题
    分组查询以及where和having的区别
    java初学复习
    Working with Excel Files in Python
    PIP常用命令
    pip install 提示代理连接失败原因及解决办法
    关于Encode in UTF-8 without BOM
    360极速浏览器Onetab插件存储位置
    使用夜神模拟器录制脚本
    微信小程序开发经验总结
  • 原文地址:https://www.cnblogs.com/lizhigang/p/7199736.html
Copyright © 2020-2023  润新知