atoi vs atol vs strtol vs strtoul vs sscanf

atoi vs atol vs strtol vs strtoul vs sscanf,c,C,我试图从正在解析的命令行中找出哪一个函数最适合将十进制、十六进制或八进制数转换为int最佳值,而无需事先知道输入 然后,目标是使用一个函数来识别不同类型的输入,并将其分配给整数(int)值,然后可以使用该值,以便: ./a.out 23 0xC4 070 可以打印 23 196 /*hexadecimal*/ 56 /*octal*/ 我能看到的唯一问题是解析十进制整数和八进制之间的差异 边问题,将字符串转换成整数以供使用吗?< p>只有考虑< STRTROR()/ >代码> Strut

我试图从正在解析的命令行中找出哪一个函数最适合将十进制、十六进制或八进制数转换为
int
最佳值,而无需事先知道输入

然后,目标是使用一个函数来识别不同类型的输入,并将其分配给整数(
int
)值,然后可以使用该值,以便:

./a.out 23 0xC4 070
可以打印

23
196 /*hexadecimal*/
56  /*octal*/
我能看到的唯一问题是解析十进制整数和八进制之间的差异


边问题,将字符串转换成整数以供使用吗?

< p>只有考虑< <代码> STRTROR()/<代码> >代码> StrutLUE()/代码>(或<代码> StrutLL())/<代码>或<代码> StrutOLL()>代码> > <代码> > Strtoimax()> <代码>或<代码> StrutMax()/<代码> <代码> <代码> >如果您关心错误条件。如果您不关心溢出时的错误条件,则可以使用其中任何一种。无论是
atoi()
还是
atol()
还是
sscanf()
都无法控制值是否溢出。此外,无论是
atoi()
还是
atol()
都不支持十六进制或八进制输入(因此实际上您无法使用它们来满足您的需求)

请注意,调用
strtoX()
函数并不是一件简单的事情。在调用它们之前,必须将
errno
设置为0,并传递一个指针以获取结束位置,然后仔细分析以了解发生了什么。请记住,这些函数的所有可能返回值都是有效的输出,但其中一些也可能指示无效的输入-和
errno
,并且结束指针帮助您区分它们

如果您需要在使用读取值后转换为
int
,例如使用
strtoll()
,您可以对照
中为
int
定义的范围检查返回值的范围(存储在
long
):
int\u MIN
int\u MAX

有关详细信息,请参阅我的答案:

请注意,这些函数都不会告诉您使用了哪种转换。您需要自己分析字符串。奇怪的提示:您知道C源代码中没有十进制0吗;当您写入
0
时,您正在写入一个八进制常数(因为它的第一个数字是
0
)。这件琐事没有实际后果

哪个函数最适合将十进制、十六进制或八进制数转换为
int
最佳(?)

要将此类文本转换为
int
,建议使用
long strtol(const char*nptr,char**endptr,int base)int
时使用code>进行附加测试

使用
0
作为
base
来评估转向转换中的早期字符,以10、16或8为基数

示例代码

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

int mystrtoi(const char *str) {
  char *endptr;
  errno = 0;
  //                                   v--- determine conversion base
  long long_var = strtol(str, &endptr, 0);
  //   out of range   , extra junk at end,  no conversion at all   
  if (errno == ERANGE || *endptr != '\0' || str == endptr) {
    Handle_Error();
  }

  // Needed when `int` and `long` have different ranges
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (long_var < INT_MIN || long_var > INT_MAX) {
    errno = ERANGE;
    Handle_Error();
  }
  #endif

  return (int) long_var;
}
#包括
#包括
#包括
int mystrtoi(常量字符*str){
char*endptr;
errno=0;
//v---确定转换基数
long_var=strtol(str和endptr,0);
//超出范围,末尾有多余的垃圾,根本没有转换
if(errno==ERANGE | |*endptr!='\0'| | str==endptr){
Handle_Error();
}
//当'int'和'long'的范围不同时需要
#如果LONG_MININT_MAX
如果(长变量<整数最小值| |长变量>整数最大值){
errno=ERANGE;
Handle_Error();
}
#恩迪夫
返回(int)长变量;
}

atoi vs atol vs strtol vs strtoul vs sscanf。。。到int

atoi()

赞成者:非常简单。
Pro:转换为
int

Pro:在C标准库中。
赞成者:快。
缺点:无错误处理。
反对:既不能处理十六进制也不能处理八进制

atol()

赞成:简单。
Pro:在C标准库中。
赞成者:快。
Con:转换为长的,而不是大小不同的整数。
缺点:无错误处理。
反对:既不能处理十六进制也不能处理八进制

strtol()

赞成:简单。
Pro:在C标准库中。
优点:良好的错误处理。
赞成者:快。
Pro:可以处理二进制文件。
缺点:转换为长的,而不是大小不同的整数

strtoul()

赞成:简单。
Pro:在C标准库中。
优点:良好的错误处理。
赞成者:快。
Pro:可以处理二进制文件。
---:似乎不抱怨负数。
Con:转换为大小可能不同的无符号长
,而不是
int

sscanf(…,%i,…)

Pro:在C标准库中。
Pro:转换为
int

---:道路中间的复杂性。
缺点:可能会变慢。
Con:OK错误处理(未定义溢出)

所有人都从
locale
设置中受益。§7.22.1.4 6“除“C”语言环境外,还可接受其他特定于语言环境的主题顺序表。”


附加学分:
errno
测试
ERANGE
atoi()
仅十进制,讨论
errno
多线程问题。
速度问题。
@凯文图书馆的包容性



转换为<代码>短>代码>代码>符号char < /代码>等,考虑.< /p> <代码> ATOI()>代码>和<代码> ATOR()>代码>与错误恢复有关的限制非常有限;code>sscanf()太复杂;使用

strtol()
strtoul()
“事先不知道输入”您的意思是不知道数字各自的基数吗?没有通用的方法可以从数字的位数推断出它的基数。例如,“70”可以是基数8、基数10或基数16。如果没有关于表示法含义的信息,没有人能解释它。通常我们使用文化民俗来传达这些信息(例如“领先0
#include <errno.h>
#include <limits.h>
#include <stdlib.h>

int mystrtoi(const char *str) {
  char *endptr;
  errno = 0;
  //                                   v--- determine conversion base
  long long_var = strtol(str, &endptr, 0);
  //   out of range   , extra junk at end,  no conversion at all   
  if (errno == ERANGE || *endptr != '\0' || str == endptr) {
    Handle_Error();
  }

  // Needed when `int` and `long` have different ranges
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (long_var < INT_MIN || long_var > INT_MAX) {
    errno = ERANGE;
    Handle_Error();
  }
  #endif

  return (int) long_var;
}