我有一个可爱的交谈与某人有关的挫折std::stoi
。 说穿了,它使用std::strtol
内部,并抛出如果报告错误。 据他们介绍,虽然std::strtol
不应该为一个输入报告错误"abcxyz"
,引起stoi
不要乱扔std::invalid_argument
。
首先,这里有两个方案关于这些案件的行为GCC测试:
与strtol
Stoi旅馆
他们都表现出对成功的"123"
和失败"abc"
。
我看着在拉更多信息标准:
§21.5
Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that
no conversion could be performed. Throws out_of_range if the converted value is
outside the range of representable values for the return type.
凝聚了依靠的行为strtol
。 现在来谈谈strtol
? 我发现这在C11草案:
§7.22.1.4
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of nptr is stored in the object
pointed to by endptr, provided that endptr is not a null pointer.
由于传递的情况"abc"
时,C标准规定nptr
,它指向字符串的开头,将存储在endptr
,传入的指针。这似乎与测试相一致。 此外,0应返回,如本声明:
§7.22.1.4
If no conversion could be performed, zero is returned.
以前的基准说,没有转换将被执行,因此它必须返回0。这些条件现在符合了C ++ 11标准stoi
投掷std::invalid_argument
。
这样做的结果关系到我,因为我不想去走一走推荐stoi
为字符串的其他方法更好的选择到int的转换,或者使用它自己就好像它的工作,你所希望的方式,如果它不”牛逼捕捉文本为无效的转换。
因此,经过这一切,我有没有出错的地方? 在我看来,我有被抛出此异常的很好的证明。 是我的证明有效,或者std::stoi
不能保证抛出异常时给出"abc"
?
是否std::stoi
扔在输入错误"abcxyz"
?
是。
我觉得你的混乱可能来自一个事实, strtol
永远不会报告错误 ,除了上溢。 它可以报告,不进行转换,但是这绝不称为C标准中的错误条件。
strtol
由所有三个C标准类似定义,我就饶了你无聊的细节,但它基本上定义了一个“目标序列”,即对应于实际数量的输入字符串的子串。 以下四种情况是等价的:
- 主题序列具有预期形式(纯英文:它是一个数字)
- 主题序列是非空
- 转换已经发生
-
*endptr != nptr
(这仅是有道理的时候endptr
不为null)
当存在溢出时,转换仍然说已发生了。
现在,它是很清楚,因为"abcxyz"
不包含数字,字符串的主题序列"abcxyz"
必须为空,以便能够执行任何转换。 下面的C90 / C99 / C11计划将实验确认:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *nptr = "abcxyz", *endptr[1];
strtol(nptr, endptr, 0);
if (*endptr == nptr)
printf("No conversion could be performed.\n");
return 0;
}
这意味着,任何符合的执行std::stoi
必须抛出invalid_argument
给出的输入时, "abcxyz"
不可选参数的基础。
这是否意味着std::stoi
具有良好的错误检查?
号你说话的人是正确的,当她说std::stoi
比进行全面检查更为宽松errno == 0 && end != start && *end=='\0'
后std::strtol
,因为std::stoi
悄悄除掉从字符串中的第一个非数字字符开始的所有字符。
其实把我的头的唯一语言的母语转换的顶部行为有点像std::stoi
是JavaScript和即使如此,你必须强制基地10 parseInt(n, 10)
避免十六进制数字的特殊情况:
input | std::atoi std::stoi Javascript full check
===========+=============================================================
hello | 0 error error(NaN) error
0xygen | 0 0 error(NaN) error
0x42 | 0 0 66 error
42x0 | 42 42 42 error
42 | 42 42 42 42
-----------+-------------------------------------------------------------
languages | Perl, Ruby, Javascript Javascript C#, Java,
| PHP, C... (base 10) Python...
注:也存在空白和冗余+符号的处理语言之间的差异。
好了,我想完全错误检查,我应该怎么用?
我不知道任何内置的功能,这是否的,但boost::lexical_cast<int>
会做你想要什么。 这是特别严格,因为它甚至拒绝周围的空白,不像Python的int()
函数。 需要注意的是无效字符和溢出导致相同的异常, boost::bad_lexical_cast
。
#include <boost/lexical_cast.hpp>
int main() {
std::string s = "42";
try {
int n = boost::lexical_cast<int>(s);
std::cout << "n = " << n << std::endl;
} catch (boost::bad_lexical_cast) {
std::cout << "conversion failed" << std::endl;
}
}