为什么当我最后离开输出编码为UTF8 csc.exe崩溃?

我遇到了一件很奇怪的事情。

我想知道是否有其他人,为什么发生。

用这行代码运行一行程序System.Console.WriteLine(System.Console.OutputEncoding.EncodingName); 我看到编码是Western European (DOS)

精细

这里列出了一些代码页1200 Unicode65001 utf-8Windows-1252 Western European (Windows)850 Western European DOS从https://msdn.microsoft.com/en-us/library/system.text.encoding (v = vs.110)的.aspx

说我写了一个C锐利的程序来改变编码为UTF-8

 class sdf { static void Main(string[] args) { System.Console.WriteLine(System.Console.OutputEncoding.EncodingName); System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(65001); System.Console.WriteLine(System.Console.OutputEncoding.EncodingName); } } 

它的作品,它打印

 Western European (DOS) Unicode (UTF-8) 

现在当我再次运行csc时,csc崩溃。

在这里输入图像说明

我使用memtest检查了我的RAM 14小时8次。 我跑了chkdsk我的硬盘,一切都好。 这绝对不是那些,这是一个编码问题。 我知道,因为如果我打开一个新的cmd提示符,然后运行csc,它不会崩溃。

所以运行这个c程序,改变了shell,以至于下一次运行csc就会使csc本身崩溃。

如果我编译下面的代码,然后运行它,然后运行csc,然后运行csc或csc whatever.cs,我得到csc崩溃。

所以closurescmd提示符,打开一个新的。

这一次,试验评论和取消注释的第二行程序

我发现,如果第二行(将代码页更改为850(DOS西欧)的行)存在,那么下次运行csc时它不会崩溃。

而如果我注释掉第二行,所以程序退出时,将代码页/编码更改为UTF-8,然后下一次csc运行,csc崩溃。

//取消最后一行的注释,然后//运行,但下一次会导致csc崩溃。

 class asdf { static void Main() { System.Console.OutputEncoding = System.Text.Encoding.UTF8; //output and to utf8 System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850); } } 

我不是唯一遇到这种事情的人

虽然没有解释发现有https://social.msdn.microsoft.com/Forums/vstudio/en-US/0e5f477e-0c32-4e88-acf7-d53d43d5b566/c-command-line-compiler-cscexe-immediately-crashes-当-在代码运行页-65001-UTF8?论坛= csharpgeneral

我可以通过确保最后一行将代码页设置为850来处理它。虽然我会解释这是一个不足的解决scheme..

另外我想知道这是CSC的一些问题,其他人也有。 或者其他解决scheme。

添加

uuu1.cs

 // uuu1.cs class asdf { static void Main() { System.Console.InputEncoding = System.Text.Encoding.UTF8; System.Console.OutputEncoding = System.Text.Encoding.UTF8; // not unicode. UTF8 means redirection will then work System.Console.WriteLine("ჵ"); // try redirecting too.. // and try checking for csc crash or not //System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850); //System.Console.InputEncoding =System.Text.Encoding.GetEncoding(850); //problem is that when that is commented, it breaks the redirection } } 

添加行/取消注释最后一行,所以我有

System.Console.OutputEncoding = System.Text.Encoding.GetEncoding(850);

将停止崩溃,但是是一个不足的解决scheme,因为例如..如果我想redirect到一个文件的程序的输出,那么我需要从头到尾一路UTF8,否则不起作用

这与代码页850行的工作未注释

 c:\blah>uuu1>rr<ENTER> c:\blah>type rr <ENTER> c:\blah>ჵ 

如果我取消注释最后一行,从而将代码页更改为850,那么确保csc不会在下次运行时崩溃,但redirect不起作用,并且rr不包含该字符。

加2

韩的回答让我注意到触发这个错误的另一种方法

 C:\Users\harvey\somecs3>csc<ENTER> Microsoft (R) Visual C# Compiler version 4.0.30319.18408 for Microsoft (R) .NET Framework 4.5 Copyright (C) Microsoft Corporation. All rights reserved. warning CS2008: No source files specified error CS1562: Outputs without source must have the /out option specified C:\Users\harvey\somecs3>chcp 65001<ENTER> Active code page: 65001 C:\Users\harvey\somecs3>csc<ENTER> <-- CRASH C:\Users\harvey\somecs3> 

那么,你发现C#编译器在切换到UTF-8时必须处理输出文本到控制台的方式有一个bug。 它有一个自我诊断,以确保从UTF-16编码的字符串转换到控制台输出代码页的工作正常,它没有时,大红色的按钮,它砰的一声。 堆栈跟踪如下所示:

 csc.exe!OnCriticalInternalError() + 0x4 bytes csc.exe!ConsoleOutput::WideToConsole() + 0xdc51 bytes csc.exe!ConsoleOutput::print_internal() + 0x2c bytes csc.exe!ConsoleOutput::print() + 0x80 bytes csc.exe!ConsoleOutput::PrintString() + 0xb5 bytes csc.exe!ConsoleOutput::PrintBanner() + 0x50 bytes csc.exe!_main() + 0x2d0eb bytes 

WideToConsole()的实际代码不可用,与SSCLI20发行版本中的最接近的匹配项是:

 /* * Like WideCharToMultiByte, but translates to the console code page. Returns length, * INCLUDING null terminator. */ int ConsoleOutput::WideCharToConsole(LPCWSTR wideStr, LPSTR lpBuffer, int nBufferMax) { if (m_fUTF8Output) { if (nBufferMax == 0) { return UTF8LengthOfUnicode(wideStr, (int)wcslen(wideStr)) + 1; // +1 for nul terminator } else { int cchConverted = NULL_TERMINATED_MODE; return UnicodeToUTF8 (wideStr, &cchConverted, lpBuffer, nBufferMax); } } else { return WideCharToMultiByte(GetConsoleOutputCP(), 0, wideStr, -1, lpBuffer, nBufferMax, 0, 0); } } /* * Convert Unicode string to Console ANSI string allocated with VSAlloc */ HRESULT ConsoleOutput::WideToConsole(LPCWSTR wideStr, CAllocBuffer &buffer) { int cch = WideCharToConsole(wideStr, NULL, 0); buffer.AllocCount(cch); if (0 == WideCharToConsole(wideStr, buffer.GetData(), cch)) { VSFAIL("How'd the string size change?"); // We have to NULL terminate the output because WideCharToMultiByte didn't buffer.SetAt(0, '\0'); return E_FAIL; } return S_OK; } 

从机器代码判断,崩溃发生在VSFAIL()声明的某处。 我可以看到返回的E_FAIL语句。 然而,它从我发布的版本改变了,if()语句被修改了,它看起来像VSFAIL()被RETAILVERIFY()所取代。 当他们做出这些改变的时候,有些东西可能在UnicodeToUTF8()中,现在被命名为UTF16ToUTF8()。 再次强调,我发布的版本实际上并没有崩溃,您可以通过运行C:\ Windows \ Microsoft.NET \ Framework \ v2.0.50727 \ csc.exe来查看自己。 只有csc.exe的v4版本有这个bug。

实际的错误很难从机器代码中挖掘出来,最好让微软担心。 您可以在connect.microsoft.com上提交该错误。 我没有看到类似的报告,相当显着顺便说一句。 解决此问题的方法是使用CHCP将代码页更改回来。

那里有不同的文章,暗示Windows控制台有许多Unicode相关的错误。 文章如: https : //alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode/

这是一个适用于我的解决方法。 代替:

 csc aaa1.cs 

试试这个(将CSC输出重定向到一个文件):

 csc /utf8output aaa1.cs > aaa1-compilation.log 

相关文档: https : //msdn.microsoft.com/en-us/library/d5bxd1x2.aspx

在一些国际配置中,编译器输出无法正确显示在控制台中。 在这些配置中,使用/ utf8output并将编译器输出重定向到一个文件。

通过障碍物添加

看着聊天,我们已经发现,做csc uuu1.cs<ENTER> uuu1<ENTER>然后为了防止崩溃,每个csc来都必须用/ utf8output AND(对于一些奇怪的未知原因),奇怪的是,用一个重定向..所以, csc /utf8output uuu1.cs >asdfsdaf

Han的解决方法是更好的,只要在uuu1<ENTER>之后运行chcp 850(或者你使用的任何代码页),即使chcp表示它是850,你仍然需要做chcp 850.然后csc将正常运行。

之所以出现问题,是因为即使chcp显示为850,也应该运行chcp 850,因为chcp只会显示输入编码,尽管chcp 850会改变输入编码和输出编码,而我们希望输出编码更改。 所以即使你的输出编码是65001,chcp也能显示850,问题只在输出编码是65001时才显示