下面的程序将字符串转换为long,但根据我的理解,它也会返回一个错误。我所依赖的事实是,如果strtol成功地将字符串转换为长整型,那么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;
}发布于 2013-01-06 04:35:34
你就快到了。temp本身不会为空,但如果整个字符串被转换,它将指向一个空字符,因此您需要取消对它的引用:
if (*temp != '\0')发布于 2013-01-06 05:30:33
请注意,以下划线开头的名称是为实现保留的;最好避免在代码中使用此类名称。因此,_val应该只是val。
当您第一次遇到strtol()及其相关的错误处理的完整规范时,它非常复杂,令人惊讶地复杂。有一件事是绝对正确的,那就是使用一个函数来调用strtol();在代码中使用它“原始”可能是不正确的。
由于这个问题同时使用了C和C++标记,我将引用C2011标准;您可以在C++标准中找到合适的措辞。
ISO/IEC9899: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如果主题序列为空或不具有预期的形式,则不执行任何转换;如果endptr不是空指针,则nptr的值存储在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()函数可能如下所示:
static long parseLong(const char *str)
{
errno = 0;
char *temp;
long val = strtol(str, &temp, 0);
if (temp == str || *temp != '\0' ||
((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
fprintf(stderr, "Could not convert '%s' to long and leftover string is: '%s'\n",
str, temp);
// cerr << "Could not convert '" << str << "' to long and leftover string is '"
// << temp << "'\n";
return val;
}请注意,出错时,这将返回0、LONG_MIN或LONG_MAX,具体取决于strtol()返回的内容。如果您的调用代码需要知道转换是否成功,则需要一个不同的函数接口-请参见下面的内容。另外,请注意,错误应该打印到stderr而不是stdout,并且错误消息应该用换行符\n终止;如果不是这样,就不能保证它们会及时出现。
现在,在库代码中,您可能不想要任何打印,而您的调用代码可能想知道转换是否成功,因此您可能还需要修改界面。在这种情况下,您可能需要修改函数,使其返回一个成功/失败指示:
bool parseLong(const char *str, long *val)
{
char *temp;
bool rc = true;
errno = 0;
*val = strtol(str, &temp, 0);
if (temp == str || *temp != '\0' ||
((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE))
rc = false;
return rc;
}你可以像这样使用它:
if (parseLong(str, &value))
…conversion successful…
else
…handle error…如果你需要区分‘尾随垃圾’,‘无效的数字字符串’,‘值太大’和‘值太小’(和‘没有错误’),你应该使用整数或enum而不是布尔返回码。如果您想要允许尾随空格,但不允许其他字符,或者如果您不想允许任何前导空格,则在函数中有更多的工作要做。代码允许八进制、十进制和十六进制;如果您想要严格的十进制,则需要在调用strtol()时将0更改为10。
如果您的函数要伪装为标准库的一部分,则它们不应该永久地将errno设置为0,因此您需要包装代码以保留errno
int saved = errno; // At the start, before errno = 0;
…rest of function…
if (errno == 0) // Before the return
errno = saved;发布于 2020-09-27 22:13:10
如何从strtol中成功检测错误?
static long parseLong(const char * str) {
int base = 0;
char *endptr;
errno = 0;
long val = strtol(str, &endptr, base);3个由标准C库指定/支持的测试:
if (str == endptr) puts("No conversion.");
else if (errno == ERANGE) puts(“输入超出长范围”);
else if (*endptr) put(“数字文本后的额外垃圾。”);
成功
else printf("Success %ld\n", val);像str == NULL或base not 0,2到36这样的输入是未定义的行为。各种实现(对C库的扩展)通过errno提供已定义的行为和报告。我们可以添加第四个测试。
else if (errno) puts("Some implementation error found.");或者与errno == ERANGE测试相结合。
示例简洁的代码,也利用了常见的实现扩展。
long my_parseLong(const char *str, int base, bool *success) {
char *endptr = 0;
errno = 0;
long val = strtol(str, &endptr, base);
if (success) {
*success = endptr != str && errno == 0 && endptr && *endptr == '\0';
}
return val;
}https://stackoverflow.com/questions/14176123
复制相似问题