问题陈述
我想将一个字符串">太棒了!"附加到另一个字符串"冰淇淋">中使用 getline 函数从 stdin 读入。
从而生产"冰淇淋真棒!
如果输入是手动键入的,则追加操作可以完美运行。
但是,如果输入是通过重定向命令"<">从文件中获取的,则追加操作的行为不会类似。
因此生产真棒! 冰淇淋。
法典
让我通过代码演示问题。
#include<iostream>
int main()
{
// err : will be read from stdin using getline
// err : is expected to fail in appending
std::string err;
// ok : will be modified internally
// ok : is expected to succeed in appending
std::string ok = "Pancakes";
std::cout<<"Before executing std::getline..."<<std::endl;
std::cout<<"err t:t"<<err<<std::endl;
std::cout<<"ok t:t"<<ok<<std::endl;
std::cout<<"-------------------"<<std::endl;
// we now use getline to read in string value for err
// stdin can have any string , let's assume it is "Ice creams"
std::cout<<"-------------------"<<std::endl;
std::cout<<"Please enter string manually or < from file "<<std::endl;
std::getline(std::cin,err);
std::cout<<"-------------------"<<std::endl;
std::cout<<"After executing std::getline..."<<std::endl;
std::cout<<"err t:t"<<err<<std::endl;
std::cout<<"ok t:t"<<ok<<std::endl;
std::cout<<"-------------------"<<std::endl;
//-------------------------------------------//
// THE PROBLEM //
//-------------------------------------------//
// we try to append to err
err += " are awesome !";
// we try to append to ok
ok += " are awesome !";
std::cout<<"After executing append operation..."<<std::endl;
std::cout<<"Where,the '+=' operator is used..."<<std::endl;
std::cout<<"err t:t"<<err<<std::endl;
std::cout<<"ok t:t"<<ok<<std::endl;
std::cout<<"-------------------"<<std::endl;
return 0;
}
端子输出
编译是在 WSL 功能的帮助下,使用 Windows 10 计算机中运行的 g++ 完成的。
C:test>wsl g++ test.cpp -o a.out -std=c++11
C:test>wsl ./a.out
Before executing std::getline...
err :
ok : Pancakes
-------------------
-------------------
Please enter string manually or < from file
Ice creams
-------------------
After executing std::getline...
err : Ice creams
ok : Pancakes
-------------------
After executing append operation...
Where,the '+=' operator is used...
err : Ice creams are awesome !
ok : Pancakes are awesome !
-------------------
C:test>wsl ./a.out < in-test.in
Before executing std::getline...
err :
ok : Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err : Ice creams
ok : Pancakes
-------------------
After executing append operation...
Where,the '+=' operator is used...
are awesome ! Ice creams
ok : Pancakes are awesome !
-------------------
C:test>
结果
- 追加为来自标准输入的手动输入生成正确的结果。
- 追加会为来自标准输入的文件in-test.in生成乱码结果。
注意:in-test.in文件包含一行字符串"冰淇淋"。
注意:如果很难注意到错误,那么让我指出它。
这是线真棒! 冰淇淋位于终端输出的尾部。
问题
- 为什么会这样?
- 如何避免?
请注意,该行甚至不包含据称前导"err t:t"
的输出,但err
的输出显示了它应该在的位置?
这只能是因为输入文件包含一个前导回车'r'
。
确认
很高兴一些程序员伙计提到'r'
可以存在于字符串中。
问题来源
有道理,Linux,Macintosh和Windows具有不同的行终止符,因此当我们想要将文件从一个系统传输到另一个系统并期望它们正常工作时,可能会出现一些问题。
在这个问题中很好地解释了:D CR LF,LF和CR换行类型之间的问题?。
事实正是如此。我使用记事本创建了该文件.exe因此自动为其分配了一个 CRLF 行终止符。但是,由于我使用Windows Subsystem for Linux(WSL((本质上是在Windows 10中运行的Ubuntu(编译程序,因此a.out
创建的可执行文件是Linux可执行文件。
将带有 CRLF 行终止符的文件重定向到可执行标准输入会导致此问题。
在使用 MinGW 或 MSYS2 后迁移到 WSL 的用户可能会遇到此特定问题。
因为,MinGW和MSYS2可以很好地与CRLF编码一起使用,但WSL不能。
修复
只需使用名为unix2dos
或dos2unix
的工具更改行终止符。
顾名思义,它们将文本文件转换为与dos和unix兼容。 基于操作系统。
- 使用使用 Linux/WSL 创建的文件时,请使用
unix2dos
,以使其与 Windows 可执行文件兼容。 - 使用使用 Windows 创建的文件时,请使用
dos2unix
,以使其与 Linux/WSL 可执行文件兼容。
演示
C:test>wsl g++ test.cpp -o a.out -std=c++11
C:test>wsl unix2dos in-test.in
unix2dos: converting file in-test.in to DOS format ...
C:test>wsl file in-test.in
in-test.in: ASCII text, with CRLF line terminators
C:test>wsl ./a.out < in-test.in
Before executing std::getline...
err :
ok : Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err : Ice creams
ok : Pancakes
-------------------
After executing append operation...
Where,the '=' operator overloading is used...
are awesome ! Ice creams
ok : Pancakes are awesome !
-------------------
C:test>wsl dos2unix in-test.in
dos2unix: converting file in-test.in to Unix format ...
C:test>wsl file in-test.in
in-test.in: ASCII text
C:test>wsl ./a.out < in-test.in
Before executing std::getline...
err :
ok : Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err : Ice creams
ok : Pancakes
-------------------
After executing append operation...
Where,the '=' operator overloading is used...
err : Ice creams are awesome !
ok : Pancakes are awesome !
-------------------
结果
WSL 创建的可执行文件最初不适用于带有 CRLF 行终止符的输入文件,然后
该文件的行终止符被更改为与Linux兼容的行终止符,因此通过使用工具
dos2unix
,导致程序的成功运行。因此,该修复程序有效。