为什么 csc.exe 在我上次将输出编码保留为 UTF8 时崩溃?

Why is csc.exe crashing when I last left the output encoding as UTF8?

我正在或已经 运行 变成一件非常难运行的事情。

我想知道其他人是否有以及为什么会这样。

有 运行 一个包含这一行的单行程序 System.Console.WriteLine(System.Console.OutputEncoding.EncodingName); 我看到编码是 Western European (DOS)

很好

这是一些代码页的列表 1200 Unicode65001 utf-8 以及 Windows-1252 Western European (Windows)850 Western European DOS 来自 https://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.110).aspx

假设我写了一个 C sharp 程序来将编码更改为 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 检查了我的内存 14 个小时,8 次通过。我运行 chkdsk 我的硬盘,一切正常。这绝对不是那些,这是一个编码问题。 我知道,因为如果我打开一个新的 cmd 提示符,然后 运行 csc,它不会崩溃。

所以 运行ning 那个 c sharp 程序,改变了 shell 这样下一次 运行ning csc 就会崩溃 csc 本身,在那个大的方式。

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

所以关闭cmd提示,打开一个新的。

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

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

而如果我注释掉第二行,那么程序将 codepage/encoding 更改为 UTF-8,然后下一次 csc 运行s,csc 崩溃。

//取消最后一行的注释,然后 // 这个 运行s 但下次 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-when-run-in-code-page-65001-utf8?forum=csharpgeneral

我可以通过确保最后一行将代码页设置为 850 来处理它。尽管我将解释这是一个不充分的解决方案..

另外我想知道这是否是其他人也有的 CSC 问题。或任何其他解决方案。

已添加

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);

会阻止崩溃,但这是一个不充分的解决方案,因为例如..如果我想将程序的输出重定向到一个文件,那么我从头到尾都需要 UTF8,否则它不会'没工作

这适用于未注释的代码页 850 行

c:\blah>uuu1>r.r<ENTER>  
c:\blah>type r.r <ENTER>  
c:\blah>ჵ  

如果我取消注释最后几行,从而将代码页更改为 850,那么确保 csc 不会在下一个 运行 崩溃,但是重定向不起作用,r.r 也不会包含那个字符。

添加了 2

Han 的回答让我注意到另一种触发此错误的方式

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>

有不同的文章暗示 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

In some international configurations, compiler output cannot correctly be displayed in the console. In these configurations, use /utf8output and redirect compiler output to a file.

由 barlop 添加[​​=36=]

查看聊天记录,我们发现执行 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

时才会出现问题

好吧,您发现了 C# 编译器在切换到 UTF-8 时必须将文本输出到控制台的处理方式中的一个错误。它具有自我诊断功能,以确保从 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, '[=11=]');
        return E_FAIL;
    }
    return S_OK;
}

从机器代码判断,崩溃发生在 VSFAIL() 断言周围的某处。我可以看到 return E_FAIL 语句。然而,它与我发布的版本有所不同,if() 语句已修改,看起来 VSFAIL() 已被 RETAILVERIFY() 取代。当他们进行这些更改时,出现了一些问题,可能是在 UnicodeToUTF8() 中,它现在被命名为 UTF16ToUTF8()。再次强调一下,我发的这个版本其实并没有崩溃,大家自己看运行 C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe。只有csc.exe的v4版本有这个bug。

真正的bug很难从机器码中挖掘出来,最好让微软去操心。您可以在 connect.microsoft.com 提交错误。我没有看到类似的报告,顺便说一句,相当了不起。此错误的解决方法是使用 CHCP 将代码页改回。