atoi vs atol vs strtol vs strtoul vs sscanf

use*_*954 16 c

我试图从正在解析的命令行中找出,哪个函数最好将十进制,十六进制或八进制数转换int为最佳数 - 不事先知道输入.

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

./a.out 23 0xC4 070
Run Code Online (Sandbox Code Playgroud)

可以打印

23
196 /*hexadecimal*/
56  /*octal*/
Run Code Online (Sandbox Code Playgroud)

我能看到的唯一问题是解析找到十进制整数和八进制之间的差异.

边题,是否可以将字符串转换为整数使用?

chu*_*ica 27

哪个函数最好将十进制,十六进制或八进制数转换为最佳的int(?)

要将此类文本转换为,请在转换时使用其他测试int建议(如果需要). intlong strtol(const char *nptr, char **endptr, int base);

使用int作为0评估操舵变换早字符作为基体10,16或8 @Mike霍尔特

0x or 0X followed by hex digits--> hexadecimal  
0 --> octal  
else --> decimal  
Run Code Online (Sandbox Code Playgroud)

示例代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

atoi vs atol vs strtol vs strtoul vs sscanf

base
亲:非常简单.
Pro:转换为atoi().
Pro:在C标准库中.
亲:快.
骗局:没有错误处理.
Con:既不处理十六进制也不处理八进制.

int
亲:简单.
Pro:在C标准库中.
亲:快.
Con:转换为a atol(),而不是long大小可能不同.
骗局:没有错误处理.
Con:既不处理十六进制也不处理八进制.

int
亲:简单.
Pro:在C标准库中.
亲:良好的错误处理.
亲:快.
Pro:可以处理二进制文件.
Con:转换为a strtol(),而不是long大小不同.

int
亲:简单.
Pro:在C标准库中.
亲:良好的错误处理.
亲:快.
Pro:可以处理二进制文件.
---:似乎没有抱怨负数.
Con:转换为a strtoul(),而不是unsigned long大小可能不同.

int
Pro:在C标准库中.
Pro:转换为sscanf(..., "%i", ...).
---:中间的复杂性.
骗局:可能很慢.
Con:OK错误处理(未定义溢出).

所有人都受益于int设置.§7.22.1.46"除"C"语言环境外,可以接受其他特定于语言环境的主题序列表格."


额外学分:
@Jonathan Leffler:locale测试errno,ERANGE仅限小数,讨论atoi()多线程问题.
@Marian Speed问题.
@Kevin图书馆的包容性.


对于转换errno,short等等,可以考虑signed char.

  • 你说''errno`可能因其他并发进程而改变'.假设s/processes/threads /符合你的意思,在线程环境中,`errno`是特定于线程的,因此没有(不应该)是一个问题.ISO/IEC 9899:2011第7.5节错误`<errno.h>`说:_`errno`扩展为可修改的左值,其类型为"int"和线程本地存储持续时间,其值设置为正误差由几个库函数编号._脚注201解释了`errno`不一定是对象的标识符(例如它可以是`*errno()`). (3认同)
  • @ArturCzajka 1) 使用 `(int) strtol (__nptr, (char **) NULL, 10);` 时,如果转换使 `long` 超出 `int` 范围,则会丢失信息 2) `(char **) NULL` 会丢失有关转换停止位置的信息。3) 出错时,实现不需要遵循 `(int) strtol (__nptr, (char **) NULL, 10);`,即使在您今天使用的编译器上这样做,出错时,行为未定义。`strtol()` 没有这些缺点。 (2认同)

Jon*_*ler 12

它是唯一明智的考虑strtol()strtoul()(或strtoll()strtoull()<stdlib.h>,或者strtoimax()或者strtoumax()<inttypes.h>)如果你关心的错误条件.如果你不关心溢出的错误条件,可以使用它们中的任何一个.无论是atoi()也不是atol(),也不sscanf()让你控制,如果值溢出.此外,既不提供atoi()也不atol()提供对十六进制或八进制输入的支持(因此实际上您不能使用它们来满足您的要求).

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

如果你需要int在使用,比如读取值后转换为strtoll(),你可以检查返回值的范围(存储在a中long long)与<limits.h>for int:INT_MIN和中定义的范围INT_MAX.

有关详细信息,请参阅我的回答:正确使用strtol().

请注意,这些函数都不会告诉您使用了哪个转换.您需要自己分析字符串.古怪的说明:你知道C源中没有小数0; 当你写作时0,你正在写一个八进制常量(因为它的第一个数字是a 0).这件琐事没有实际的后果.