Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3. 数值字符串转换函数

#include <stdlib.h>

int atoi(const char *nptr);
double atof(const char *nptr);
返回值:转换结果

atoi 把一个字符串开头可以识别成十进制整数的部分转换成int 型,相当于下面要讲的strtol(nptr, (char **) NULL, 10); 。例如atoi("123abc") 的返回值是 123,字符串开头可以有若干空格,例如atoi(" -90.6-") 的返回值是-90。如果字符串开头没有可识别的整数,例如atoi("asdf") ,则返回 0,而atoi("0***") 也返回 0,根据返回值并不能区分这两种情况,所以使用atoi 函数不能检查出错的情况。下面要讲的strtol 函数可以设置errno ,因此可以检查出错的情况,在严格的场合下应该用strtol ,而atoi 用起来更简便,所以也很常用。

atof 把一个字符串开头可以识别成浮点数的部分转换成double 型,相当于下面要讲的strtod(nptr, (char **) NULL); 。字符串开头可以识别的浮点数格式和 C 语言的浮点数常量相同,例如atof("31.4 ") 的返回值是 31.4,atof("3.14e+1AB") 的返回值也是 31.4。atof 也不能检查出错的情况,而strtod 可以。

#include <stdlib.h>

long int strtol(const char *nptr, char **endptr, int base);
double strtod(const char *nptr, char **endptr);
返回值:转换结果,出错时设置 errno

strtol atoi 的增强版,主要体现在这几方面:

  • 不仅可以识别十进制整数,还可以识别其它进制的整数,取决于 base 参数,比如 strtol("0XDEADbeE~~", NULL, 16) 返回 0xdeadbee 的值, strtol("0777~~", NULL, 8) 返回 0777 的值。

  • endptr 是一个传出参数,函数返回时指向后面未被识别的第一个字符。例如char *pos; strtol("123abc", &pos, 10); strtol 返回 123,pos 指向字符串中的字母 a。如果字符串开头没有可识别的整数,例如char *pos; strtol("ABCabc", &pos, 10); ,则strtol 返回 0,pos 指向字符串开头,可以据此判断这种出错的情况,而这是atoi 处理不了的。

  • 如果字符串中的整数值超出 long int 的表示范围(上溢或下溢),则 strtol 返回它所能表示的最大(或最小)整数,并设置 errnoERANGE ,例如 strtol("0XDEADbeef~~", NULL, 16) 返回 0x7fffffff 并设置 errnoERANGE

回想一下使用 fopen 的套路 if ( (fp = fopen(...)) == NULL) { 读取 errno }fopen 在出错时会返回 NULL ,因此我们知道需要读 errno ,但 strtol 在成功调用时也可能返回 0x7fffffff,我们如何知道需要读 errno 呢?最严谨的做法是首先把 errno 置 0,再调用 strtol ,再查看 errno 是否变成了错误码。Man Page 上有一个很好的例子:

例 25.10. strtol 的出错处理

#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[])
{
	int base;
	char *endptr, *str;
	long val;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	str = argv[1];
	base = (argc > 2) ? atoi(argv[2]) : 10;

	errno = 0;    /* To distinguish success/failure after call */
	val = strtol(str, &endptr, base);

	/* Check for various possible errors */

	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 parsed a number */

	printf("strtol() returned %ld\n", val);

	if (*endptr != '\0')        /* Not necessarily an error... */
		printf("Further characters after number: %s\n", endptr);

	exit(EXIT_SUCCESS);
}

strtod atof 的增强版,增强的功能和strtol 类似。