如何检测转换是否在 c++0x 中失败

How to detect if the conversion failed in c++0x

本文关键字:是否 c++0x 失败 转换 何检测 检测      更新时间:2023-10-16

我尝试执行字符串到整数的转换,如下所示:

#include<iostream>
#include<sstream>
#include<string>
int main(int argc, char ** argv)
{
    int i;
    char *str = "12a3";
    std::stringstream ss;
    ss << str;
    ss >> i;
    std::cout << i << std::endl; //prints 12
}

演示

但结果不是我所期望的。我是Java,所以老实说,我一直在等待抛出一些异常。但事实并非如此。是否可以在没有旧atoi功能的情况下以安全的方式执行此类转换。

请注意,我C++0x因此无法使用std::stoi.

这是

正确的行为。>>int的操作成功,这是正确的。

你必须问一个不同的问题。您真正想要执行的测试是:"成功读取int后,流中是否还有剩余且尚未处理的字符?

考虑cin .当你这样做时

int x, y;
std::cin >> x;
std::cin >> y;

它尽可能多地从标准输入读取x,停在第一个非数字。然后,如果第一个数字后面只有一些空格,那么它将尝试读取空格后面的数字并将该数字存储在 y 中。

所有输入流(无论是cin还是实例stringstream)都应包含许多字符串/数字/任何内容。每个>>都只是尽可能多地读取(成功)。

我知道的最简单的方法。

int main(int argc, char ** argv)
{
    std::string num;
    long i;
    char *str = "12a3";
    char * endp;
    std::stringstream ss;
    ss << str;
    ss >> num;
    i = strtol(num.c_str(), // string to convert as a C style string, 
               &endp, //pointer to be updated with character that ended the conversion
               10); //base of number conversion
    if (*endp != '')
    {
        //didn't read whole string. conversion failed
    }
    std::cout << i << std::endl; //prints 12
}

您需要测试不成功的流读取和不完整的流读取:

ss >> i;
if (!ss || !ss.eof()) {
  throw std::invalid_argument("Could not convert to int");
}

在注释中,我们得出结论,您的目标是确定字符串是否仅由数字的有效表示形式组成。

C 和扩展C++一直专注于流 I/O,因此也专注于类似流的数字转换。 这样做的结果是scanfistream >>atoistrol都停止在不是有效数字的一部分的第一个字符处。

然后,您的目标是确定输入是否已完全使用,或者是否存在尾随的"垃圾"字符。 最简单的方法是使用 strtol,它将返回指向第一个未使用字符的指针。

char * endptr;
long i = strtol (str, &endptr, 10); 
bool valid = *endptr == '';

如果您的输入如下所示:"123",这仍然会失败,因为扫描将在"3"后面的空格字符处停止。

如果你的要求是尾随空格是可以接受的,你的代码将需要检查调用后从 *endptr 开始的字符串,以确定它是否是可接受的后缀,或者它可以在执行测试之前修剪输入字符串。

当运算符>>找到它无法使用的结果时,它会在流上设置failbit,流本身的计算结果将false

if(!(ss >> i)) {  // or ss >> i; if(!ss) or if(ss.fail())
    // the conversion failed, do whatever you need to here.
    ss.clear(); // reset the fail flag so you can read from the stream again
    // you can use ss.ignore() to skip bad input if you want to move on to other parts
}