C# 当我上次将输出编码保留为UTF8时,为什么csc.exe会崩溃?
我遇到了一件非常奇怪的事情 我想知道其他人是否有,为什么会这样 已经用这一行C# 当我上次将输出编码保留为UTF8时,为什么csc.exe会崩溃?,c#,windows,command-line,csc,C#,Windows,Command Line,Csc,我遇到了一件非常奇怪的事情 我想知道其他人是否有,为什么会这样 已经用这一行System.Console.WriteLine(System.Console.outpunecoding.EncodingName)运行了一行程序我看到编码是西欧(DOS) 好的 下面是一些代码页的列表 1200 Unicode和65001 utf-8和Windows-1252西欧(Windows)和850西欧DOS来自 假设我写了一个C sharp程序,将编码改为utf-8 class sdf { static
System.Console.WriteLine(System.Console.outpunecoding.EncodingName)运行了一行程序代码>我看到编码是西欧(DOS)
好的
下面是一些代码页的列表
1200 Unicode
和65001 utf-8
和Windows-1252西欧(Windows)
和850西欧DOS
来自
假设我写了一个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,它不会崩溃
因此,运行c sharp程序,改变shell,使得下一次运行csc时,csc本身会以如此大的方式崩溃
如果我编译下面的代码,然后运行它,然后运行csc,然后运行csc,或者csc which.cs,我会让csc崩溃
所以关闭cmd提示符,打开一个新的
这一次,尝试注释和取消注释程序的第二行
我发现如果第二行(将代码页更改为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);
}
}
我不是唯一一个遇到这种事情的人
虽然没有找到任何解释
我可以通过确保最后一行将代码页设置为850来解决这个问题。尽管我会解释这是一个不合适的解决方案
此外,我想知道这是否是CSC的一些问题,其他人也有。或任何其他解决方案
已添加
uu1.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.outpunecoding=System.Text.Encoding.GetEncoding(850)
将停止崩溃,但这是一个不合适的解决方案,因为例如..如果我想将程序的输出重定向到一个文件,那么从头到尾我都需要UTF8,否则它不起作用
这适用于未注释的代码页850行
c:\blah>uuu1>r.r<ENTER>
c:\blah>type r.r <ENTER>
c:\blah>ჵ
c:\blah>uu1>r.r
c:\blah>键入r.r
c:\blah>ჵ
如果我取消最后几行的注释,从而将代码页更改为850,那么确保csc不会在下一次运行时崩溃,但重定向不起作用,r.r不包含该字符
增加了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:\Users\harvey\somecs3>csc
Microsoft(R)Visual C#编译器版本4.0.30319.18408
适用于Microsoft(R).NET Framework 4.5
版权所有(C)微软公司。保留所有权利。
警告CS2008:未指定源文件
错误CS1562:没有源的输出必须指定/out选项
C:\Users\harvey\somecs3>chcp 65001
活动代码页:65001
C:\Users\harvey\somecs3>csc
有不同的文章提示Windows控制台存在许多与Unicode相关的错误。例如:
以下是一个适合我的解决方法。而不是:
csc aaa1.cs
尝试以下操作(将CSC输出重定向到文件):
相关文件:
在某些国际配置中,编译器输出无法在控制台中正确显示。在这些配置中,请使用/utf8output并将编译器输出重定向到文件
由巴洛普添加
查看chat,我们发现执行csc uuu1.cs
uu1
,然后为了防止崩溃,每个csc都必须使用/utf8output完成,而且(出于一些奇怪的未知原因),奇怪的是,还需要重定向..因此,csc/utf8output uuuu1.cs>asdfsdaf
不过,Han的解决方法更好,只要在uuu1
之后运行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, '\0');
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亲自查看。只有v4版本的csc.exe存在此错误
从机器代码中很难找出真正的错误,最好让微软担心一下。你可以在connect.micros上存档错误
/*
* 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;
}