简体   繁体   English

C ++:帮助Linux和Windows之间的cin区别

[英]C++: Help with cin difference between Linux and Windows

I have a Win32 console program that I wrote and it works fine. 我有一个我写的Win32控制台程序,它工作正常。 The program takes input from the user and performs some calculations and displays the output - standard stuff. 该程序从用户获取输入并执行一些计算并显示输出 - 标准内容。 For fun, I am trying to get the program to work on my Fedora box but I am running into an issue with clearing cin when the user inputs something that does not match my variable type. 为了好玩,我试图让程序在我的Fedora盒子上工作,但是当用户输入与我的变量类型不匹配的东西时,我遇到了清除cin的问题。 Here is the code in question: 这是有问题的代码:

void CParameter::setPrincipal() {
double principal = 0.0;

cout << endl << "Please enter the loan principal: ";
cin >> principal;

while(principal <= 0)
{
    if (cin.fail())
    {
          cin.clear();
          cin.ignore(INT_MAX, '\n');
    }
    else
    {
        cout << endl << "Plese enter a number greater than zero. Please try again." << endl;
        cin >> principal;
    }
}

m_Parameter = principal;

} }

This code works in Windows. 此代码适用于Windows。 For example, if the user tries to enter a char data type (versus double) then the program informs the user of the error, resets cin, and allows the user another opportunity to enter a valid value. 例如,如果用户尝试输入char数据类型(相对于double),则程序会通知用户错误,重置cin,并允许用户再次输入有效值。

When I move this code to Fedora, it compiles fine. 当我将此代码移动到Fedora时,它编译得很好。 When I run the program and enter an invalid data type, the while loop never breaks to allow the user to change the input. 当我运行程序并输入无效的数据类型时,while循环永远不会中断以允许用户更改输入。

My questions are; 我的问题是; how do I clear cin when invalid data is inputted in the Fedora environment? 如何在Fedora环境中输入无效数据时清除cin? Also, how should I write this code so it will work in both environments (Windows & Linux)? 此外,我应该如何编写此代码,以便它可以在两种环境(Windows和Linux)中工作?

Thanks in advance for your help! 在此先感谢您的帮助!

I think that cin.ignore sets the failed flag on cin , which makes it stay in the upmost if statement for ever. 我认为cin.ignorecin上设置了失败的标志,这使得它永远保持在最高的if语句中。 INT_MAX is a very large number - are you sure it is allowed to cin.ignore on all platforms? INT_MAX是一个非常大的数字 - 你确定它允许在所有平台上使用cin.ignore吗?

I'd switch to using a getline to read the input and then parse with a stringstream : 我转而使用getline来读取输入,然后使用stringstream进行解析:

double principal = 0;
string temp;
while (principal <= 0)
{
    getline(cin, temp);
    istringstream converter(temp);
    if (!(converter>>principal) ||
        !(converter>>std::ws).eof() ||
        principal <= 0)
    {
        cout << "Try again" << endl;
        principal = 0;
    }
}

I think it's a bad idea to use formatted input to read user responses. 我认为使用格式化输入来读取用户响应是个坏主意。 I'd use getline - something like this: 我使用getline - 这样的东西:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

template <typename T>
bool Read( T & t, istream & is ) {
    string s;
    if ( ! getline( is, s ) ) {
        return false;
    }
    else {
        istringstream ss( s );
        return ss >> t;
    }
}    

int main() {
    while(1) {
        double d;
        if ( ! Read( d, cin ) ) {
            cout << "invalid\n";
        }
        else {
            cout << "You entered " << d << "\n";
        }
    }
}

which works on Windows - I don't have my Linux box switched on at the moment. 在Windows上运行 - 我目前没有打开我的Linux机箱。

I agree with Anders Abel and Johannes Schaub; 我同意Anders Abel和Johannes Schaub; I think also that it may not be guaranteed that, in case of error, principal is left untouched, so you may consider adding principal=0.0; 我认为也可能无法保证,如果出现错误,主体保持不变,因此您可以考虑添加principal=0.0; at the beginning of the cycle. 在周期的开始。

By the way, to perform that kind of work I usually use this template function: 顺便说一下,为了执行这种工作,我通常使用这个模板功能:

template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
    do
    {
        Os<<Prompt.c_str();
        if(Is.fail())
        {
            Is.clear();
            Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
        Is>>Result;
        if(Is.fail())
            Os<<FailString.c_str();
    } while(Is.fail());
}

template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
    InType temp;
    AcquireInput(Os,Is,Prompt,FailString,temp);
    return temp;
}

The first overload may be preferred if you want to avoid copying, the second may be more convenient for builtin types. 如果你想避免复制,第一个重载可能是首选,第二个可能更适合内置类型。 Usage examples: 用法示例:

//1st overload
double aDouble;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",aDouble);

//2nd overload (more convenient, in this case and in general with POD)
double aDouble=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");

In your case you may change your code in this way: 在您的情况下,您可以通过以下方式更改代码:

double principal=0.0;
const char * errMsg="Plese enter a number greater than zero. Please try again.\n";
while(principal<=0.0)
{
    principal=0.0;
    principal=AcquireInput(cout,cin,"Please enter the loan principal: ",errMsg);
    if(principal<=0.0)
        cout<<errMsg;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM