在C ++中使用istringstream

时间:2018-11-27 01:12:54

标签: c++ fork exec wait istringstream

我有一些利用fork,execlp和等待进行两个处理的代码。目的是能够重复打印提示,并让用户输入最多包含4个参数/选项的命令。

int main()
{
     string command, argument;
     istringstream iss(argument);

  do
  {
  //prompt user for command to run
  cout << "Enter command: ";
  cin >> command >> argument;

  int pid, rs, status;

  //fork will make 2 processes
  pid = fork();
  if(pid == -1) { perror("fork"); exit(EXIT_FAILURE); }

if(pid == 0) {
//Child process: exec to command with argument

//C_str to get the character string of a string
rs = execlp(command.c_str(), command.c_str(), argument.c_str(), (char*) NULL);
.
if (rs == -1) { perror("execlp"); exit(EXIT_FAILURE); }
} else {
   //Parent process: wait for child to end
   wait(&status);
      }
   } while(command != "exit");

   return 0;
}

我知道当前的代码只能支持该命令的一个参数,但是我不确定要使用什么来指定1到4个参数。那时,我的一个朋友向我提到了std::istringstream,但是在研究它时,我不知道如何在程序的其余部分中将其用于输入。有没有办法设置它,或者有其他方法可以用来满足要求?

2 个答案:

答案 0 :(得分:3)

std::istringstream在用户输入中最常见的用法是接受一行文本,然后对其进行处理。这样可以避免当输入与您的预期不匹配或无法预测时可能发生的问题。

这是一个简单的示例,它一次从STDIN读取一行,并将其处理为命令,然后是字符串向量作为参数。

for(std::string line; std::getline(std::cin, line); )
{
    std::istringstream iss(line);

    std::string command;
    if (iss >> command)
    {
        std::vector<std::string> args;
        for (std::string arg; iss >> arg; )
        {
            args.push_back(arg);
        }
        std::cout << "Received '" << command << "' with " << args.size() << " arguments\n";
    }
    else
    {
        std::cerr << "Invalid input" << std::endl;
    }
}

当然,您不需要读入字符串,也不需要将内容存储在向量中。这只是出于说明目的。

基本要点是避免人们遇到的陷阱,其中最常见的是期望先前的流操作成功。如果这个假设是错误的,那么天真的程序员可能会发现自己正在尝试解析应该在上一行中处理过的内容。


残破的示例:

#include <iostream>

int main() {
    std::string command;
    while (std::cin >> command)
    {
        std::cout << "Got command: " << command << std::endl;
        if (command == "foo")
        {
            // 'foo' expects two integer arguments:
            int arg1, arg2;
            std::cin >> arg1 >> arg2;
            std::cout << command << ": " << arg1 << ", " << arg2 << std::endl;
        }
        else if (command == "bar")
        {
            // 'bar' expects one float argument:
            float arg1;
            std::cin >> arg1;
            std::cout << command << ": " << arg1 << std::endl;
        }
    }
    return 0;
}

在上面,假设用户感到困惑,并使用一个float参数“调用” foo 命令,那么下一个命令是有效的 bar 命令:< / p>

foo 42.0
bar 3.14

发生了什么事

  1. foo 处理程序将arg1读取为42,然后无法读取下一个参数。流现在有错误。

  2. 在该处理程序期间未对输入进行任何错误检查,因此现在存在输出arg2的值的不确定行为。

  3. 尝试读取下一条命令时,流已经处于错误状态,因此循环终止。

因此,该程序的输出可能类似于:

Got command: foo
foo: 42, -149017896

可以解决不使用istringstream的问题,但这很痛苦。流可能会进入错误状态的原因有很多,而清除特定错误状态的错误标志只是为了解决此问题,这会使代码变得丑陋且容易出错。您不仅需要清除错误标志,而且还需要告诉流忽略该行中的所有剩余字符。而且您可能已经不知道就开始阅读 next 行。


更强大的示例:

#include <iostream>
#include <sstream>

int main() {
    std::string command;
    for (std::string line; std::getline(std::cin, line); )
    {
        std::istringstream iss(line);
        if (!(iss >> command))
            continue;
        std::cout << "Got command: " << command << std::endl;
        if (command == "foo")
        {
            // 'foo' expects two integer arguments:
            int arg1, arg2;
            if (iss >> arg1 >> arg2)
            {
                std::cout << command << ": " << arg1 << ", " << arg2 << std::endl;
            }
        }
        else if (command == "bar")
        {
            // 'bar' expects one float argument:
            float arg1;
            if (iss >> arg1)
            {
                std::cout << command << ": " << arg1 << std::endl;
            }
        }
    }
    return 0;
}

现在,与上一个示例相同的输入将给出输出:

Got command: foo
Got command: bar
bar: 3.14

区别是:

  • 使用istringstream,处理输入的任何错误都不会影响源流,因此上一行的失败不会引起问题。

  • 在读取参数时正确检查了字符串流,从而允许进行可选的错误处理。

  • 如果在某些解析失败后您决定尝试以不同方式处理一行输入,那么使用另一个字符串流就很容易。

答案 1 :(得分:1)

如果我正确理解了您的作业,那么您的明显问题就在这里:

 cin >> command >> argument;

您需要一个包含整个命令行的字符串(getline?)。然后,您需要一个绑定到保存整个命令行的字符串的istringstream。

然后您需要做类似的事情

iss >> command >> arg1 >> arg2 >> arg3 >> arg4 ;

这时,我对您的作业要求一无所知。但是,您可能想要执行以下操作:

iss >> command >> arg1 >> arg2 >> arg3 >> arg4 >> arg5 ;

用于错误检查。如果arg5不是一个空字符串,则说明指定了太多参数。