原文: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/,否则一旦发现,将按字节每人民币收费,绝不论价]

字符数字转换 atoi 与 strtol的更多相关文章

  1. 比较java与c语言中数字转换成字符的不同

    java java中将数字转换成字符非常方便,只要用一个"+"然后在跟一个空格行了.比如,你输入一个122 ,就会变成"122 ". import java.u ...

  2. Halcon中循环读取文件的实现以及数字与字符的转换

    在循环读取文件的位置时,常用到数字与字符的转换. 数字与字符的转换 将字符转换为数字 tuple_number(StringImageIndex,IntImageIndex)` 1 2 1 2 将数字 ...

  3. js将数字转换成货币形式的字符

    因为UI图上有的地方需要将数字转成货币形式的,例如:1234567转成  1,234,567  这样的,不过之前没弄过,然后在网上搜了下方法,参考了下面这篇文章 参考文章:JS将数字转成货币形式的简单 ...

  4. c语言字符串 数字转换函数大全

    最近学数据结构老是做实验 常用到字符串和数字的转换 想找却发现网上的资料太散 所以搜集整理一下 方便以后再用 atof(将字符串转换成浮点型数) atoi(将字符串转换成整型数) atol(将字符串转 ...

  5. iconv字符编码转换

    转自 http://blog.csdn.net/langresser_king/article/details/7459367 iconv(http://www.gnu.org/software/li ...

  6. unicode编码、字符的转换和得到汉字的区位码

    一:unicode编码.字符的转换截图 二:unicode编码.字符的转换代码 using System; using System.Collections.Generic; using System ...

  7. 编码问题 php字符编码转换类

    各种平台和软件打开显示的编码问题,需要使用不同的编码,根据我们不同的需求. php 字符编码转换类,支持ANSI.Unicode.Unicode big endian.UTF-8.UTF-8+Bom ...

  8. js字符串转换成数字与数字转换成字符串的实现方法

    转载:点击查看地址 js字符串转换成数字 将字符串转换成数字,得用到parseInt函数.parseInt(string) : 函数从string的开始解析,返回一个整数. 举例:parseInt(' ...

  9. js字符串转换成数字,数字转换成字符串

    转自网络,忘记出处了. js字符串转换成数字 将字符串转换成数字,得用到parseInt函数. parseInt(string) : 函数从string的开始解析,返回一个整数. 举例:parseIn ...

随机推荐

  1. HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)

    http://acm.hdu.edu.cn/showproblem.php?pid=5442 题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样 ...

  2. python使用easyinstall安装xlrd、xlwt、pandas等功能模块的方法

    在日常工作中,使用Python时经常要引入一些集成好的第三方功能模块,如读写excel的xlrd和xlwt模块,以及数据分析常用的pandas模块等. 原生的python并不含这些模块,在使用这些功能 ...

  3. linux下普通用户添加 sudo 免密码

    在使用普通用户登录的时候,会经常使用sudo指令执行一些操作,有时候感觉输入密码比较繁琐,特别是需要设置一些开机启动的时候操作,而这些操作往往就需要sudo指令,如果没有免密的话,在使用普通用户登录的 ...

  4. $bzoj1019-SHOI2008$ 汉诺塔 $dp$

    题面描述 汉诺塔由三根柱子(分别用\(A\ B\ C\)表示)和\(n\)个大小互不相同的空心盘子组成.一开始\(n\)个盘子都摞在柱子\(A\)上,大的在下面,小的在上面,形成了一个塔状的锥形体. ...

  5. Unix_JDK安装及配置

    CentOS 下过程 JDK 在 CentOS 和 Ubuntu 下安装过程是一样的,所以这里不再讲 Ubuntu 系统下的安装 JDK 1.8 下载 此时(20170906)最新版本:jdk-8u1 ...

  6. Hive动态分区 参数配置及语法

    Hive本身是不支持动态分区的.. 但动态分区是真的方便啊..不然手动维护要累死..按日期甚至小时来分区时动辄就好几千上万的分区..手动到哪一年去..? 想要用动态分区要先做一些设置来修改默认的配置. ...

  7. unity对敏感词库处理的记录

    string txt = Resources.Load<TextAsset>("minganci").ToString(); //string txt = " ...

  8. linux 查看端口,开启新端口

    一.查看端口被占用命令 1.lsof -i:端口号 2.netstat -tunlp|grep 端口号 3.netstat -anp 查看哪些端口被打开 上面命令是查看端口被进程占用的情况 二.开启新 ...

  9. Struts2拦截器和标签

    一.struts2拦截器 1.struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面. 2 struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都执行,每 ...

  10. TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.Internal.IHttpResponseStreamWriterFactory' from assembly 'Microsoft.AspNetCore.Mvc.Core, Version=2.1.2.0 ...

    今天调试 asp.net core 2.0 项目时遇到了如下错误: TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.I ...