我该如何检测strtol()未转换数字的情况? 我在以下简单示例上测试了它,它输出为0。 现在显而易见的问题是,我如何区分非转换和转换为0?
long int li1;
li1 = strtol("some string with no numbers",NULL,10);
printf("li1: %ld\n",li1);
****
li1: 0
我该如何检测strtol()未转换数字的情况? 我在以下简单示例上测试了它,它输出为0。 现在显而易见的问题是,我如何区分非转换和转换为0?
long int li1;
li1 = strtol("some string with no numbers",NULL,10);
printf("li1: %ld\n",li1);
****
li1: 0
stdio.h
中,strtol
的声明如下:long int strtol(const char *nptr, char **endptr, int base);
strtol
提供了一个强大的错误检查和验证方案,使您能够确定返回的值是 valid
还是 invalid
。实际上,您有三个主要工具可用。 (1) 返回的值,(2) 调用时设置的值 errno
,以及 (3) 提供给 strtol
的 nptr
和 endptr
的地址和内容。 (请参见完整详情请参阅 man 3 strtol
- 在 man
页面的示例也提供了一组更短的条件进行检查,但以下内容已扩展以进行解释)。
在您的情况下,您询问有关返回值为 0
并确定它是否有效的问题。如您所见,strtol
返回的 0
值不表示读取的数字为 0
或者 0
是有效的。要确定 0
是否有效,您还必须查看调用期间设置的值 errno
(如果已设置)。具体而言,如果 errno != 0
并且由 strtol
返回的值为 0
,则由 strtol
返回的值是INVALID。(这种情况将表示 invalid base
、underflow
或 overflow
,且 errno
等于 EINVAL
或 ERANGE
)。
还有第二种情况会导致 strtol
返回 INVALID 的 0
。即输入中没有读取到数字的情况。当发生这种情况时,strtol
将 endptr == nptr
的值设为 0
。因此,在得出输入了 0
时,您还必须检查指针值是否相等。(可以在字符串中键入多个 0
来输入一个VALID的 0
)
以下提供了一个简短的示例,说明了评估 strtol
返回值时要检查的不同错误条件以及几种不同的测试条件:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main (int argc, char **argv)
{
if (argc < 2) {
fprintf (stderr, "\n Error: insufficient input. Usage: %s int [int (base)]\n\n", argv[0]);
return 1;
}
const char *nptr = argv[1]; /* string to read */
char *endptr = NULL; /* pointer to additional chars */
int base = (argc > 2) ? atoi (argv[2]) : 10; /* numeric base (default 10) */
long number = 0; /* variable holding return */
/* reset errno to 0 before call */
errno = 0;
/* call to strtol assigning return to number */
number = strtol (nptr, &endptr, base );
/* output original string of characters considered */
printf ("\n string : %s\n base : %d\n endptr : %s\n\n", nptr, base, endptr);
/* test return to number and errno values */
if (nptr == endptr)
printf (" number : %lu invalid (no digits found, 0 returned)\n", number);
else if (errno == ERANGE && number == LONG_MIN)
printf (" number : %lu invalid (underflow occurred)\n", number);
else if (errno == ERANGE && number == LONG_MAX)
printf (" number : %lu invalid (overflow occurred)\n", number);
else if (errno == EINVAL) /* not in all c99 implementations - gcc OK */
printf (" number : %lu invalid (base contains unsupported value)\n", number);
else if (errno != 0 && number == 0)
printf (" number : %lu invalid (unspecified error occurred)\n", number);
else if (errno == 0 && nptr && !*endptr)
printf (" number : %lu valid (and represents all characters read)\n", number);
else if (errno == 0 && nptr && *endptr != 0)
printf (" number : %lu valid (but additional characters remain)\n", number);
printf ("\n");
return 0;
}
输出:
$ ./bin/s2lv 578231
string : 578231
base : 10
endptr :
number : 578231 valid (and represents all characters read)
$ ./bin/s2lv 578231_w_additional_chars
string : 578231_w_additional_chars
base : 10
endptr : _w_additional_chars
number : 578231 valid (but additional characters remain)
$ ./bin/s2lv 578some2more3stuff1
string : 578some2more3stuff1
base : 10
endptr : some2more3stuff1
number : 578 valid (but additional characters remain)
$ ./bin/s2lv 00000000000000000
string : 00000000000000000
base : 10
endptr :
number : 0 valid (and represents all characters read)
$ ./bin/s2lv stuff578231
string : stuff578231
base : 10
endptr : stuff578231
number : 0 invalid (no digits found, 0 returned)
$ ./bin/s2lv 00000000000000000 -2
string : 00000000000000000
base : -2
endptr : (null)
number : 0 invalid (base contains unsupported value)
EINVAL
的讨论反映了非标准的 C 库实现扩展。对 strtol()
的错误检查不需要涉及 EINVAL
的测试(如“不是所有的 c99 实现 - gcc OK”所建议的),但当存在 EINVAL
时,可能会受益于提供额外的细节。 - chux - Reinstate Monicaerrno
是有意义的,例如当 nptr == NULL
或无效的 base
时,因此 else if (errno)
是一个很好的捕获方式。 - chux - Reinstate Monica