【发布时间】:2021-08-13 13:02:09
【问题描述】:
我正在尝试在 C# 中写入进程(C++ 程序)的标准输入。问题是 C++ 程序似乎无法读取我从 C# 应用程序中编写的内容。以下是这两个程序:
// C#
static void Main(string[] args) {
Console.InputEncoding = Encoding.Unicode;
Console.OutputEncoding = Encoding.Unicode;
Process CoutN = new Process();
CoutN.StartInfo.FileName = @"C:\Users\Vesk\Desktop\CoutN.exe";
CoutN.StartInfo.UseShellExecute = false;
CoutN.StartInfo.RedirectStandardInput = true;
CoutN.StartInfo.RedirectStandardOutput = false;
CoutN.Start();
CoutN.StandardInput.WriteLine("5");
CoutN.WaitForExit();
Console.ReadKey();
}
// C++
int main() {
int n;
std::cin >> n;
std::cout << "N is " << n << std::endl;
return 0;
}
这是我的 C# 程序的输出:N is 0。它应该是N is 5。
据我所知,C# 用于进程输入/输出流的编码与控制台使用的编码相同。事情是这样的,在我的 C# 程序中,我需要能够使用控制台输入西里尔文文本(以及其他非 ASCII 文本)。唯一似乎适用的控制台编码是Encoding.Unicode(显然只是UTF-16 LE)。
但是当我尝试写入进程的输入流时,它似乎无法理解,并且由于某种原因它输出N is 0。据我了解,这是因为 UTF-16 与 ASCII 不兼容(或 C++ iostream 所期望的)。
那么有没有办法真正改变进程的标准输入使用的编码?
这是我尝试过/不能尝试的:
- 我不想更改控制台的编码,因为我打算以异步运行的方式运行进程,并且我希望仍然能够与C#程序交互,所以我担心它会搞砸,即使我只是更改编码,也只是在写入进程然后再将其更改回来。
- 我知道 C++ 程序可能会被更改,以便它可以读取 UTF-16,但我不想这样做,因为我的 C# 程序必须能够运行并与各种“接口” C++ 程序,使用简单的
iostream(cin,cout)。 (编辑澄清:我的 C# 程序只需要向 C++ 程序“发送”ASCII 文本) - 我确实尝试将控制台的编码更改为
Encoding.ASCII,并且成功了。如果我只是将控制台保留为默认编码,它也可以工作。但这又对我不起作用,因为这些编码似乎不适用于西里尔文。 - 我尝试将控制台的输入编码设置为
Encoding.UTF8,但没有成功,尽管无论如何我都无法使用它,因为它似乎不适用于我的 C# 应用程序中的西里尔文文本。 - 我尝试更改
CoutN.StandardInput.Encoding,但不幸的是它是一个只读属性。 - 我还尝试重定向标准输出,只是为了看看它是否有效,而且奇怪的是它确实有效。我可以只使用
CoutN.StandardOutput.ReadToEnd(),它可以正常工作并且C++程序的输出被正确读取(尽管仍然说N is 0)。但由于某种原因,标准输入有所不同。 - 我试图不重定向标准输入,再次只是为了看看它是否有效,但又一次非常奇怪的是它成功了!。我刚刚在 C# 程序的控制台中写了
5,输出为N is 5。 - 我尝试使用不同的编码创建
StreamWriter并从那里写入:
StreamWriter str = new StreamWriter(CoutN.StandardInput.BaseStream, Encoding.ASCII);
str.WriteLine("5");
但这也不起作用。我什至尝试了基本上所有的编码,甚至没有编码,但没有任何效果。
- 我尝试自己写信给
BaseStream:
byte[] buffer = Encoding.ASCII.GetBytes("5");
CoutN.StandardInput.BaseStream.Write(buffer, 0, buffer.Length);
CoutN.StandardInput.WriteLine();
那没有用。
在这一点上,我觉得我已经用尽了所有可以尝试的选项。任何帮助表示赞赏,在此先感谢!
【问题讨论】:
-
STD 输入和输出是流,它们没有编码。当 应用程序 将从流中读取的字节转换为文本时,将应用编码。由于 Windows 是一个 Unicode 操作系统,而 .NET 字符串是 Unicode,所以不应该有任何改变的理由。绝对不要使用甚至无法处理所有英文文本的 7 位 US-ASCII 代码页
-
问题出在 C++ 代码中,而不是 C#。您正在尝试从标准输入中读取,就好像它包含单字节文本一样。很可能,该程序也被编译为 ASCII 而不是 Unicode。自 1990 年代末、2000 年代初以来,Windows 应用程序不以这种方式编译,这正是因为操作系统是 Unicode 并且 Windows 已在全世界范围内使用。虽然在 C++ 中使用 Unicode 很棘手,因为标准化过程非常很慢。虽然现在有
char16_t、char32_t、u16string和u32string类型,但在 C++ 20 之前没有明确的 UTF8 类型。 -
你所说的 ASCII 是 7 位的 ASCII,它甚至不能处理所有的英文文本,比如
Charlotte Brontë。它不被任何操作系统或进程使用。同样,您要问的是如何破坏 C# 程序以避免修复 C++ 错误,这是任何 C++ Windows 应用程序都不应该有的。 -
与其询问如何更改 C# 编码,不如询问 C++ 编码是什么 - 除非您指定一个,否则它是对应于机器语言环境的那个,不是 ASCII。区域设置中的标签甚至显示
Locale used by non-Unicode programs。甚至美国机器也使用 Latin1,而不是 ASCII。这在 C# 程序中显示为Encoding.Default,因为它就是这样 - 处理非 Unicode I/O 时的默认编码。 -
长话短说。使用
Console.OutputEncoding = Encoding.Default;甚至完全删除该行。更好的是,修复 C++ 错误。在 Unicode 操作系统上使用char和string是完全错误的,这种错误在 2000 年就消失了。
标签: c# c++ input encoding process