关于错误的atoi()的行为,我可以假设什么?

fuz*_*fuz 6 c atoi undefined-behavior language-lawyer

标准C库函数atoi在ISO 9899:2011中记录为:

7.22.1数字转换函数

1的功能atof,atoi,atol,和atoll需要不影响整数表达式的值errno上的误差.如果无法表示结果的值,则行为未定义.

...

7.22.1.2的atoi,atolatoll功能

概要

#include <stdlib.h>
int atoi(const char *nptr);
long int atol(const char *nptr);
long long int atoll(const char *nptr);
Run Code Online (Sandbox Code Playgroud)

描述

2 atoi,atolatoll函数转换字符串的初始部分指向nptrint,long intlong long int表示,分别.除了出错的行为,它们相当于

atoi: (int)strtol(nptr, (char **)NULL, 10)
atol: strtol(nptr, (char **)NULL, 10)
atoll: strtoll(nptr, (char **)NULL, 10)
Run Code Online (Sandbox Code Playgroud)

返回

3 atoi,atol以及atoll函数返回转换后的值.

当指向的字符串nptr无法解析为整数时,预期的行为是什么?以下四种观点似乎存在:

  • 不执行转换,返回零.这是一些像这样的参考文献给出的文档.
  • 行为就是这样的strtol,只是errno可能没有设置.这是从"除错误行为之外"中引出的,作为对第7.22.1节的参考.
  • 行为未指定.这就是POSIX所说的:

    呼叫atoi(str)应相当于:

    (int) strtol(str, (char **)NULL, 10)
    
    Run Code Online (Sandbox Code Playgroud)

    除了错误的处理可能不同.如果无法表示该值,则行为未定义.

    此外,应用程序使用部分说明:

    atoi()函数由strtol()包含但保留,因为它在现有代码中广泛使用.如果未知该数字在范围内,则应使用strtol(),因为不需要atoi()来执行任何错误检查.

    请注意,POSIX声称该规范与ISO 9899:1999一致(就我而言,它包含与ISO 9899:2011相同的语言):

    此参考页面上描述的功能与ISO C标准一致.此处描述的要求与ISO C标准之间的任何冲突都是无意的.本卷POSIX.1-2008符合ISO C标准.

    据我当地的POSIX委员会成员说,这是UNIX的历史行为.

  • 行为未定义.这种解释的产生是因为§7.22.1.22从未明确说明错误发生了什么.既未定义也未明确实现已定义或未指定的行为未定义.

哪些解释是正确的?请尝试参考权威文档.

chu*_*ica 3

\n

当字符串指向时,预期的行为是什么nptr无法解析为整数时,预期的行为是什么?

\n
\n\n

需要明确的是,这个问题适用于

\n\n
// Case 1\nvalue = atoi("");\nvalue = atoi("  ");\nvalue = atoi("wxyz");\n
Run Code Online (Sandbox Code Playgroud)\n\n

而不是以下内容:

\n\n
// Case 2\n// NULL does not point to a string\nvalue = atoi(NULL);\n// Convert the initial portion, yet has following junk\nvalue = atoi("123xyz");\nvalue = atoi("123 ");\n
Run Code Online (Sandbox Code Playgroud)\n\n

根据整数的使用,可能/可能不是以下内容的使用情况,可能/可能不是以下内容。

\n\n
// Case 3\n// Can be parsed as an _integer_, yet overflows an `int`.\nvalue = atoi("12345678901234567890123456789012345678901234567890");\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

的“非情况 2”行为取决于错误ato*()的含义取决于

\n\n
\n

、和函数分别将指向atoi的字符串的初始部分转换为、和表示形式。除了error上的行为外,它们相当于\n \n \n C11dr \xc2\xa77.22.1.2 2atolatollnptrintlong intlong long int
atoi: (int)strtol(nptr, (char **)NULL, 10)
...

\n
\n\n
\n\n

当然错误包括情况3:“如果正确值超出了可表示值的范围”。 strto*(),尽管可能不是ato*(),在这种情况下确实设置了 中定义的错误号。由于 的规范不适用于此错误,因此溢出结果为 UB 每errrno<errno.h>ato*()

\n\n
\n

未定义的行为在本国际标准中通过文字 \xe2\x80\x98\xe2\x80\x98undefinedbehavior\xe2\x80\x99\xe2\x80\x99 或通过省略任何明确的行为定义来表示。C11dr \xc2\xa74 2

\n
\n\n
\n\n

对于情况 1, 的行为strto*()已明确定义,并且未指定影响errno。规范详细介绍了 (\xc2\xa77.22.1.4 4) 并称这些为“无转换”,而不是错误。因此它可以断言情况 1 的strto*()行为不是错误,而是“无转换”。因此每...

\n\n
\n

“如果无法执行转换,则返回零。C11dr \xc2\xa77.22.1.4 8

\n
\n\n

...atoi("")必须返回 0。

\n

  • @chux:从 1989 年到大约 2000 年,可能会做任何奇怪的事情的实现比例已经下降到几乎没有。然而,从那时起,使用 UB 作为借口将时间法则和因果关系抛到九霄云外就变得很流行,因此除非或直到有一个健全的 C 核心方言标准,否则防止奇怪的代码量所需的代码量是巨大的。行为会增加。 (2认同)