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