C库函数-strtol()详解及源代码分析
C库函数-strtol()
help的音标概述
strtol()是C库函数,其功能是⽤于将字符串转换成整数。函数原型为
long int strtol(const char*str,char**endptr,int ba)
该函数将str所指向的字符串根据给定的ba转换为⼀个long int型的长整数,ba必须介于2和36之间,或者是特殊值0。
参数
str:要转换为长整数的字符串
endptr:对类型为char* 的对象的引⽤,其值由函数设置为str中数值后的下⼀个字符。
ba:基数,必须介于2和36之间,或者是特殊值0。ba代表的采⽤的进制⽅式。如ba值为2就代表采⽤的⼆进制。当ba值为0时则是采⽤10进制做转换。当遇到"0x"前置字符则会采⽤16进制做转换。
功能
开始时,strtol会扫描nptr所指向的字符串,这时它会跳过⾮法字符,如:空格。直到遇见数字或者"+、—“号才开始转换,再遇到⾮数字或者”\0"时结束转换。并将结果返回(返回长整型的整数)。
返回值
饭的成语返回转换之后的长整型数,否则对异常返回并且设置errno。
左边绿
⼏点说明
1. strtol会从nptr所指向字符串的头不开始查找,当遇到数字或"+、-"时就开始转换,遇到其他的字符则停⽌转换并返回。如果字符串中
穿插着两串数字,则只会对第⼀串数字进⾏转换。
2. 如果endptr不是NULL,strtol()会将第⼀个⽆效的字符的地址⽅到*enptr。
3. 如果字符串中没有数字,strtol()会将nptr的初始值,存储到endptr中,并且返回0。
例程
#include<stdlib.h>
#include<limits.h>
#include<stdio.h>
一维度#include<errno.h>
int main(int argc,char*argv[])
{
int ba;
char*endptr,*str;
long val;
if(argc <2){
fprintf(stderr,"Usage: %s str [ba]/n", argv[0]);
/
*⽬的是从命令⾏获取字符串,如果在命令⾏没有输⼊字符串则会退出。*/
exit(EXIT_FAILURE);
}
str = argv[1];//获取命令⾏的第⼀个字符串
摘录笔记ba =(argc >2)?atoi(argv[2]):10;
/*如果命令⾏没有输⼊ba值,则默认为10,即按照⼗进制进⾏输出。atoi()函数是将字符串转换成相应的整数*/
errno =0;
/*对调⽤结束之后的结果进⾏分析(避免'0'的影响),因为错误和字符传中只含有0时返回值都是0,但错误时会重置errno,此时就可以通过errno来区分⼆者*/ val =strtol(str,&endptr, ba);
/* 检查不同的错误*/
if((errno == ERANGE &&(val == LONG_MAX || val == LONG_MIN))||(errno !=0&& val ==0)){
perror("strtol");
exit(EXIT_FAILURE);
}
if(endptr == str){
fprintf(stderr,"No digits were found/n");
exit(EXIT_FAILURE);
}
/* If we got here, strtol() successfully pard
a number */
printf("strtol() returned %ld/n", val);
/* Not necessarily */
if(*endptr !='/0')
printf("Further characters after number: %s/n", endptr);
exit(EXIT_SUCCESS);
}
<;注:上⾯这段程序是Linux中strtol()函数帮助⽂档中⼀个例⼦程序,我在相应的部分添加了注释>
该函数功能和使⽤其实还是挺简单的,多敲⼏个例⼦基本就可以摸清楚怎么玩⼉。
源码
下⾯附上该函数实现的源码,有兴趣的同学可以琢磨⼀下。
long strtol(const char* restrict nptr,char** restrict endptr,int ba)
{
教学设计格式
const char*s;
unsigned long acc;
char c;
unsigned long cutoff;
bikes怎么读
int neg, any, cutlim;
s = nptr;
do{
c =*s++;
c =*s++;
}while(isspace((unsigned char)c));
if(c =='-'){
neg =1;
c =*s++;//去掉前导空格和+ - 符号
}el{
neg =0;
if(c =='+')
c =*s++;
}
//判断进制,并去除前导0x或者0
if((ba ==0|| ba ==16)&&
c =='0'&&(*s =='x'||*s =='X')&&
((s[1]>='0'&& s[1]<='9')||
(s[1]>='A'&& s[1]<='F')||
(s[1]>='a'&& s[1]<='f'))){
c = s[1];
s +=2;
ba =16;
}
if(ba ==0)
ba = c =='0'?8:10;
acc = any =0;
if(ba <2|| ba >36)
goto noconv;
/*判断溢出的⽅法:
cutoff为系统能够表⽰的最⼤数除以ba的结果,也就是当前进制能够表⽰的最⼤有效的数。
例如32为系统下长整形的范围是[-2147483648..2147483647],如果ba是10的话,则cutoff就是
214748364,⽽cutlim就是7(正整数)或者8(负整数)。如果当前算得的值⼤于cutoff就溢出了,或者等于cutoff但是下⼀位⼤于cutlim也就溢出了*/
cutoff = neg ?(unsigned long)-(LONG_MIN + LONG_MAX)+ LONG_MAX
: LONG_MAX;
cutlim = cutoff % ba;
cutoff /= ba;
for(;; c =*s++){
if(c >='0'&& c <='9')
c -='0';
el if(c >='A'&& c <='Z')
c -='A'-10;
el if(c >='a'&& c <='z')
c -='a'-10;秋天简笔画
el
break;
if(c >= ba)
break;
//如果溢出则设置any为负数
if(any <0|| acc > cutoff ||(acc == cutoff && c > cutlim))
any =-1;
el{
any =1;
acc *= ba;
acc += c;
}
}
if(any <0){//如果溢出就返回最⼤能表⽰的值
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
}el if(!any){
noconv:
errno = EINVAL;
}el if(neg)
acc =-acc;
if(endptr !=NULL)
*endptr =(char*)(any ? s -1: nptr);
*endptr =(char*)(any ? s -1: nptr);
return(acc);
}
<;注:其中关键字restrict是C99引⼊的,它只⽤于限定和约束指针并标明指针是访问⼀个数据对象的唯⼀且初始的⽅式,**即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,⽽不能通过其他途径(其他变量或指针)来修改;**这样做的好处是:**能帮助编译器进⾏更好的有优化代码,⽣成更有效率的汇编代码。**如上⾯char * restrict nptr表明ptr指向的内存单元只能由访问到,其他任何同样指向这个内存单元的其他指针都是未定义的,即⽆效指针(野指针)>