原文: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. ABP相关网站

    ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 系列文章 ...

  2. Java正则表达式-匹配正负浮点数

    记录缘由: 公司项目需要从xml中获取标识为NUMBER的字符串,将之存入数据库中,存入的列的类型即为NUMBER.当遇到非数字时,原实现是通过异常: String plainValue = null ...

  3. Netstat 的 10 个基本用法

    Netstat 简介 Netstat 是一款命令行工具,可用于列出系统上所有的网络套接字连接情况,包括 tcp, udp 以及 unix 套接字,另外它还能列出处于监听状态(即等待接入请求)的套接字. ...

  4. MySQL表级约束和列级约束

    对一个数据列建立的约束,称为列级约束 对多个数据列建立的约束,称为表级约束 列级约束即可以在列定义时生命,也可以在列定义后声明. 表级约束只能在列定义后声明. NOT NULL和DEFAULT只存在列 ...

  5. Clojure 开发环境 light table 和 Leiningen 安装指引

    1 首先下载 Light table 然后 解压到到一文件夹.目录中千万不能有空格 下载地址 http://www.lighttable.com/ 2下载构建工具 下载地址 http://leinin ...

  6. Android ListView分组显示

    ListView的实现方法也是普通的实现方法.只不过在list列表中加入groupkey信息.在渲染的时候要判断是否是分组的标题. 就是在使用不同的两个View的时候存在这种情况,convertVie ...

  7. C#(Winform)禁用TextBox控件的鼠标事件

    1. 继承TextBox,然后重写父类的部分方法,核心代码如下 public class MyTextBox : TextBox { protected override void WndProc(r ...

  8. idea maven install 卡住,无报错排查。

    今天使用idea打包,执行install,看控制台日志,卡主了(意思是日志不继续在控制台输打印了,卡主了,也看不到错误),也没有报错,然后进行排查. 进入dos命令,进入到项目的根目录,使用 运行 m ...

  9. JS将文件像form表单一样提交到后台

    这是很简单.. HTML <div> <input type="file" id="myfile"> <input type=&q ...

  10. Centos7 linux 安装 redis 遇到的几个问题

    环境:centos7 + redis 5.0  解决方案仅供参考,如不能解决问题,请查找请他方案.     1.不能编译没有GCC 编译工具 make报错: make[1]: [persist-set ...