strtoull函数是否总是返回有效的数字或设置错误码errno?

4

strtoull是否保证会返回有效的数字,或者在无法解析有效数字时设置errno

换句话说,这是否如下所示:

errno = 0;
n = strtoull(s, 0, 10);
if (errno) {
  perror(s);
  exit(1);
}
// do something with n

是否正确,还是需要其他的检查?


2
注意:C标准并没有规定如果无法进行转换,则必须设置errno — 参见C11 §7.22.1.4 The strtol, strtoll, strtoulstrtoull functions。实现时,可能会设置 errno,但根据C标准,这不是强制性的。(在我打字的时候,问题同时被标记为C和C++)。我今天没有检查C++标准是否也是如此。另请参见Correct usage of strtol。根据标准,需要进行更多的检查。 - Jonathan Leffler
1个回答

5

否。C标准(至少草案N1570到N2454的§7.22.1.7,因此为C11到C18)仅在一个地方提到设置errno

如果正确的值不在可表示值的范围内,则根据返回类型和值的符号(如果有)返回LONG_MINLONG_MAXLLONG_MINLLONG_MAXULONG_MAXULLONG_MAX,并将宏ERANGE的值存储在errno中。

然而,还有另外一个可能的错误条件。“如果没有进行转换,则返回零”,“如果endptr不是空指针,则将nptr的值存储在endptr所指向的对象中。”否则,将在那里存储指向“最终字符串”的指针,该指针与nptr相比较会更大。

因此,真正符合标准的C程序应检查这两个条件。使用clang -std=c18在Windows 10上编译的测试程序如下:

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

int main (void) {
  const char s[] = "a1";

  errno = 0;
  char* unparsed = NULL;
  const unsigned long long int n =
    strtoull( s, &unparsed, 10 );
  
  if ( errno || (!n && s == unparsed) ) {
    fflush(stdout); // Don't cross the streams!
    perror(s);
    exit(EXIT_FAILURE);
  }
  
  printf( "%llu\n", n );
  return EXIT_SUCCESS;
}

在这个实现中,errno没有被设置,因此输出为a1: No error

正如chqrlie在评论中提到的那样,检查( errno || s == unparsed )已经足够。如果这两个条件都不成立,则对非空主题序列执行了转换。


2
检查 n 的值似乎是多余的。如果找到了一个数字,unparsed 将会 > s ,所以只需写:if (errno || s == unparsed) - chqrlie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接