下面的程序将字符串转换为long,但根据我的理解,它也返回一个错误。我依赖的事实是,如果strtol
成功地将string转换为long,那么strtol
的第二个参数应该等于NULL。当我用55运行下面的应用程序时,我得到以下消息。
./convertToLong 55
Could not convert 55 to long and leftover string is: 55 as long is 55
如何成功检测strtol
的错误?在我的应用程序中,零是一个有效值。
代码:
#include <stdio.h>
#include <stdlib.h>
static long parseLong(const char * str);
int main(int argc, char ** argv)
{
printf("%s as long is %ld\n", argv[1], parseLong(argv[1]));
return 0;
}
static long parseLong(const char * str)
{
long _val = 0;
char * temp;
_val = strtol(str, &temp, 0);
if(temp != '\0')
printf("Could not convert %s to long and leftover string is: %s", str, temp);
return _val;
}
5条答案
按热度按时间dfuffjeb1#
请注意,以下划线开头的名称是为实现保留的;最好避免在代码中使用此类名称。因此,
_val
应该是val
。strtol()
及其相关的错误处理的完整规范非常复杂,当您第一次遇到它时,复杂得令人惊讶。有一件事您做得非常正确,那就是使用一个函数来调用strtol()
;在代码中使用“原始”可能是不正确的。由于这个问题同时使用了C和C++,我将引用C2011标准;你可以在C++标准中找到适合自己的措辞。
ISO/IEC 9899:2011 §7.22.1.4
strtol
、strtoll
、strtoul
和strtoull
函数long int strtol(const char * restrict nptr, char ** restrict endptr, int base);
¶2 [...]首先,它们将输入字符串分解为三个部分:初始的、可能为空的空白字符序列(由isspace函数指定)、类似于以由base的值确定的某个基数表示的整数的主题序列、以及一个或多个未识别字符的最终字符串,包括输入字符串的终止空字符。[...]
¶7如果主题序列为空或没有预期的形式,则不执行转换;
nptr
的值存储在endptr
所指向的对象中,前提是endptr
不是空指针。返回
¶8
strtol
,strtoll
,strtoul
和strtoull
函数返回转换后的值。如果无法执行转换,则返回零。如果正确的值超出了可表示值的范围,则返回LONG_MIN、LONG_MAX、LLONG_MIN、LLONG_MAX、ULONG_MAX或ULLONG_MAX(根据返回类型和值的符号,如果有的话),宏ERANGE的值存储在errno
中。请记住,没有标准的C库函数会将
errno
设置为0。因此,为了可靠,必须在调用strtol()
之前将errno
设置为零。所以,你的
parseLong()
函数可能看起来像:请注意,如果出现错误,将返回0或LONG_MIN或LONG_MAX,具体取决于
strtol()
返回的内容。如果你的调用代码需要知道转换是否成功,你需要一个不同的函数接口--见下文。另外,请注意,错误应该打印到stderr
而不是stdout
,并且错误消息应该以换行符\n
结束;如果不是,就不能保证它们会及时出现。现在,在库代码中,您可能不希望任何打印,并且您的调用代码可能想知道转换是否成功,因此您可能也要修改接口。在这种情况下,您可能会修改函数,使其返回成功/失败指示:
你可以使用如下:
如果你需要区分'trailing junk','invalid numeric string','value too big'和'value too small'(以及'no error'),你应该使用一个整数或
enum
而不是布尔返回码。如果您希望允许白色但不允许其他字符,或者如果您不希望允许任何前导空格,则在函数中需要做更多的工作。代码允许八进制、十进制和十六进制;如果你想要严格的十进制,你需要在调用strtol()
时将0改为10。如果你的函数要伪装成标准库的一部分,它们不应该永久地将
errno
设置为0
,所以你需要 Package 代码来保留errno
:5uzkadbs2#
你就快成功了
temp
本身不会为null,但如果整个字符串被转换,它将指向一个null字符,因此您需要取消引用它:ggazkfy83#
如何成功检测strtol中的错误?
标准C库指定/支持的3个测试:
1.是否已完成转换?
1.在射程内?
1.跟踪垃圾?
成功案例
像
str == NULL
或base
这样的输入不是0,[2到36]是 undefined behavior。各种实现(C库的扩展)通过errno
提供定义的行为和报告。我们可以添加第四个测试。或者合并
errno == ERANGE
测试。示例简洁代码,也利用了常见的实现扩展。
ie3xauqp4#
你错过了一个间接的层次。你想检查字符是否是终止符
NUL
,如果指针是NULL
则不检查:顺便说一下,这不是一个很好的错误检查方法。
strto*
系列函数的正确错误检查方法不是通过比较输出指针和字符串的结尾来完成的。它应该通过检查零返回值并获取errno
的返回值来完成。disho6za5#
你应该检查一下
您还应该能够在调用strotol之后检查errno的值,如下所示: