天天看点

atoi 函数族和 strtol 函数族的区别与联系

atoi 函数族和 strtol 函数族都用来将字符串转换成数字。但是具体的区别和联系是什么呢?

通过查看 glibc 的函数源码,可以清楚的看到两者的关系。

两个函数族函数返回类型的对应关系。

返回类型 atoi函数族 strol函数族
int atoi
long atol strtol
long long atoll strtoll
float strtof
double atof strtod

函数原型

long atol(const char *nptr);
 long int strtol(const char *nptr, char **endptr, int base);
           

atoi 函数族的 glibc 实现:

atoi 的 glibc 实现:有一个强制类型转换

/* Convert a string to an int.  */
int
atoi (const char *nptr)
{
  return (int) strtol (nptr, (char **) NULL, 10);
}
           

atol 的 glibc 实现

/* Convert a string to a long int.  */
long int
atol (const char *nptr)
{
  return strtol (nptr, (char **) NULL, 10);
}
           

atoll 的 glibc 实现

/* Convert a string to a long long int.  */
long long int
atoll (const char *nptr)
{
  return strtoll (nptr, (char **) NULL, 10);
}
           

atof 的 glibc 实现

/* Convert a string to a double.  */
double
atof (const char *nptr)
{
  return strtod (nptr, (char **) NULL);
}
           

两者的关系说明。

从以上代码可以看出,

atoi 函数族是 strtol 函数族的一种特例

以 atol 为例

/* Convert a string to a long int.  */
long int
atol (const char *nptr)
{
  return strtol (nptr, (char **) NULL, 10);
}
           

通过代码可以看出,atol 只是 strtol 在 10 进制下,且不考虑错误处理的情况下特殊情况。

atol 胜在易用性,但是不能进行其他进制的解析和错误处理。

注意:

虽然,atol 由 strtol实现,因此也会设置 errno,但是 errno 只有以下两种返回值:

  • EINVAL (not in C99): 进制值输入错误(支持的进制 [2, 36],即算上字母所能表达的数字范围)
  • ERANGE: 结果超出范围

因此不能通过 errno 判断以下情况解析是否正确:

  • “abc”

    atol 会返回 0,无法判断字符串是 “0” 还是未解析正确。

  • “123abc”

    atol 会返回 123, 但是后续的 “abc” 将无法继续解析。

strtol 的使用示例

以下示例取自 man 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);
}
           

继续阅读