Почему сбой csc.exe, когда я последний раз оставил кодировку вывода как UTF8?

У меня есть или я столкнулся с очень странной вещью.

Интересно, есть ли у других и почему это происходит.

Запустив однострочную программу с этой строкой System.Console.WriteLine(System.Console.OutputEncoding.EncodingName);, я вижу, что кодировка Western European (DOS)

Fine

Вот список некоторых кодовых страниц 1200 Unicode и 65001 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 аварийно завершает работу.

enter image description here

Я проверил свою RAM на 14 часов, 8 проходов, с memtest. Я бегал chkdsk на свой жесткий диск, все в порядке. И это определенно не те, это проблема кодирования. Я знаю, потому что, если я открою новую подсказку cmd, тогда запустите csc, она не сработает.

Итак, запустив эту острую программу, она меняет оболочку таким образом, что в следующий раз только что запущенная csc сама вылетает csc. Таким образом,

Если я скомпилирую код ниже, запустите его, затем запустите csc, затем запустите csc или csc what.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); 
  }
}

Я не единственный человек, который столкнулся с чем-то вроде этого

хотя здесь не найдено никаких объяснений 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

Ответ Хан заставляет меня заметить другой способ вызвать эту ошибку

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>

Ответ 1

Ну, вы обнаружили ошибку в том, как компилятор С# имеет дело с необходимостью выводить текст на консоль, когда он переключается на 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(), судя по коду машины. Я могу видеть выражение E_FAIL. Однако было изменено с версии, которую я опубликовал, инструкция if() была изменена, и похоже, что VSFAIL() был заменен на RETAILVERIFY(). Что-то сломалось, когда они внесли эти изменения, вероятно, в UnicodeToUTF8(), который теперь называется UTF16ToUTF8(). Повторяя, версия, которую я опубликовал, на самом деле не сбой, вы можете убедиться сами, запустив C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe. Только версия vs версии csc.exe имеет эту ошибку.

Исправлена ​​ошибка, связанная с ошибкой, из-за которой машинный код можно было бы отладить. Вы можете указать ошибку на сайте connect.microsoft.com. Я не вижу отчета, похожего на него, довольно примечательного кстати. Обходной путь для этой ошибки заключается в том, чтобы использовать CHCP для изменения кодовой страницы.

Ответ 2

Существуют разные статьи, которые указывают на то, что в консоли 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

В некоторых международных конфигурациях вывод компилятора не может быть правильно отображен в консоли. В этих конфигурациях используйте /utf 8output и перенаправьте вывод компилятора в файл.

, добавленный barlop

глядя на чат, мы обнаружили, что при выполнении csc uuu1.cs<ENTER> uuu1<ENTER>, чтобы предотвратить сбой, каждый csc должен выполняться с /utf 8output И (по какой-то нечетной неизвестной причине), странно, с переадресацией. поэтому csc /utf8output uuu1.cs >asdfsdaf

Хан обходной путь лучше, хотя, просто запустите chcp 850 (или любую другую кодовую страницу, которую вы используете) после uuu1<ENTER>, даже если chcp говорит об этом 850, вам все равно придется делать chcp 850. Тогда csc будет работать нормально.

Причина того, что при возникновении проблемы вы должны запустить chcp 850, даже если chcp показывает 850, заключается в том, что chcp будет показывать только входную кодировку, хотя chcp 850 изменит как входную кодировку, так и выходную кодировку, и мы хотим изменить кодировку вывода. Таким образом, chcp может отображать 850, даже когда ваша выходная кодировка составляет 65001, и проблема возникает только тогда, когда выходная кодировка составляет 65001