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

时间: 2024-10-12 03:36:49

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

SQL 字符 数字 转换字母

1.将字符中数字转换为中文大写的数字, 注意 100==>一零零   而非==>一百 123==>一二三   而非==>一百二十三 CREATE FUNCTION Fn_NumberConvertChinase(@number NVARCHAR(50)) RETURNS NVARCHAR(20) AS BEGIN DECLARE @res NVARCHAR(20) DECLARE @char CHAR(1) SET @res = '' SET @char = substring(@

Python数字,字符格式转换笔记

好记性不如烂笔头,有一些常用的数字,字符串转换的学习笔记 1. 将二进制数转换为指定格式的字符串形式 先来看一小段代码 >>> a = 0b0100 >>> print a 4 >>> print format(a, '#0b') 0b100 >>> print format(a, '0b') 100 >>> print format(a, '04b') 0100 >>> print format(

将数字转换成字符的问题

class Solution { public List<String> fizzBuzz(int n) { List<String> list = new ArrayList<String>(); for(int i = 1;i <= n;i++){ if(i % 3 == 0 && i % 5 == 0){ list.add("FizzBuzz"); }else if(i % 3 == 0){ list.add("

C语言 字符串和数字转换函数

atof(将字符串转换成浮点型数) 相关函数 atoi,atol,strtod,strtol,strtoul 表头文件 #include <stdlib.h> 定义函数 double atof(const char *nptr); 函数说明 atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回.参数nptr字符串可包含正负号.小数点或E(e)来表示指数部分,如123.456或123e-2.

iconv字符编码转换

转自 http://blog.csdn.net/langresser_king/article/details/7459367 iconv(http://www.gnu.org/software/libiconv/)是一个开源的字符编码转换库,可以"方便"的完成几乎所有的编码转换工作.说简单是因为,它常用的接口就三个,iconv_open  iconv   iconv_close,但是即便是只有三个接口,要想使用正确也不容易.这里把一些基本概念和使用细节记录下来,希望能成为一篇最实用的

字符编码转换说明及深浅copy介绍

编码说明: 常用编码介绍: ascii 数字,字母 特殊字符. 字节:8位表示一个字节. 字符:是你看到的内容的最小组成单位. abc : a 一个字符. 中国:中 一个字符. a : 0000 1011 unicode: 万国码 起初: a : 0000 1011 0000 1011 中: 0000 1011 0000 1111 升级: a : 0000 1011 0000 1011 0000 1011 0000 1011 中: 0000 1011 0000 1111 0000 1011 00

synchronized/java.util.concurrent.locks.Loc/如何格式化日期/将字符“12345”转换成long型

1.简述synchronized和java.util.concurrent.locks.Lock的异同?解答:主要相同点:Lock能完成synchronized所实现的所有功能 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能.synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放. 2.如何格式化日期解答:Date now=new Date();SimpleDateFormat sdf=new SimpleDate

javascript实现unicode与字符互相转换

javascript实现unicode与字符互相转换. <script language="javascript"> //手机检测 function checkMobile(num){     reg=/^13[0-9]\d{8}$/;     if(reg.test(num)){         return true;     }else{         reg=/^15[8-9]\d{8}$/;         if(reg.test(num)){         

JS 字符unicode转换函数

/**js Unicode编码转换*/ var decToHex = function(str) {    var res=[];    for(var i=0;i < str.length;i++)        res[i]=("00"+str.charCodeAt(i).toString(16)).slice(-4);    return "\\u"+res.join("\\u");}var hexToDec = function(s