Замечания: Я спрашиваю поведение, определяемое реализацией, в Microsoft Visual C ++ 2008 (возможно, то же самое в 2005+). ОС: упрощенная китайская установка Win7.
Меня удивляет, когда я выполняю ввод / вывод без ASCII printf
, Например.
// This won't be necessary as it's the system default code page.
//system("chcp 936");
// NULL to show current locale, which is "C"printf ("%s\n", setlocale(LC_ALL, NULL));
printf ("中\n");
printf ("%s\n", setlocale(LC_ALL, "English"));
printf ("中\n");
Выход:
Active code page: 936
C
中
English_United States.1252
?D
Объем памяти в отладчике показывает, что "中"
кодируется двумя байтами: 0xD6
, 0xD0
, который является кодовой точкой этого символа в кодовой странице 936, для упрощенного китайского языка. Это не должно быть в диапазоне кодовой точки "C" locale
который, более вероятный, является 0x0 ~ 0x7F
,
Вопрос:
Почему он по-прежнему может правильно отображать символ в локали «C»? Таким образом, я предположил, что локаль не имела никакого отношения к printf
? Но тогда я спрошу, почему он не может больше отображаться при переходе на "English"
локаль, которая тоже отличается от 936? Интересно?
Редактировать:
Я перенаправил стандартный вывод в файл и прошел некоторый тест. Это показывает, что независимо от того, какая локаль установлена, правильный символ "中"
сохраняется в файле. Это говорит о том, что setlocale()
связано с тем, как консоль отображает символ, что противоречит моему пониманию того, как она работает: printf
помещает байты / кодовые точки во входной буфер консоли, который интерпретирует эти байты, используя свою собственную кодовую страницу (что chcp
возвращается).
936 — довольно хитрая кодовая страница, она допускает 2 символа символа (аналогично UTF-8). Например, кириллица (866) — не допускает двухбайтовые символы, и ее поведение будет таким же, как «английский».
Поэтому, когда вы используете кодовую страницу по умолчанию (936), она знает, как обрабатывать 2-символьные символы, в то время как «английский» имеет дело с 0x0 ~ 0x7f
только.
Позвольте мне также ответить, почему wprintf(L"中")
выходит из строя. Между консольным приложением и приложением Windows-окна есть большая разница, они используют разные кодовые страницы
Следуйте за совпадениями между консолью и окнами:
DOS | Windows
------+----------
850 | 1252
936 | 54936
866 | 1251
Поэтому, если вы хотите видеть в консоли правильные символы, используйте WideCharToMultiByte
первое — это обеспечивает ожидаемое преобразование, чтобы позволить работу консоли в 936
Тот факт, что языковой стандарт C печатает строку в точности так, как указано, неудивителен. Это то, что я ожидал. Что удивительно, так это то, что английский язык будет делать что-то другое.
Согласно сделать локальная документация на MSDN, единственный эффект, который должен иметь язык на printf
находится в определении символа радиуса для числовых значений (то есть десятичной точки).
Я подозреваю, что, возможно, это ошибка в компиляторе Microsoft. Или, по крайней мере, это недокументированное поведение.
Как бы то ни было, на моем компиляторе (Borland) локаль не влияет на вывод этих строк. Это действительно влияет на основание, хотя.
ХОРОШО. Для локали «C» по умолчанию CRT предполагает, что символы передаются printf
не нужно никакого преобразования. У этого есть причина, потому что символы ASCII почти всегда попадают в базовый набор символов системы выполнения (совместно используемый различными кодовыми страницами Windows). Когда он переключен на «английский», он предполагает, что ввод закодирован в кодовой странице 1252, и, таким образом, пытается выполнить преобразование с «английского» на «китайский», который является языком, используемым консолью. Но ЭЛТ просто не может найти персонажа 中
в кодовой странице 1252. Вот почему он выводит знак вопроса.
При перенаправлении в файл CRT знает об этом и не будет выполнять преобразование, поскольку кодовая страница консоли больше не используется. Он просто проходит через байты как есть. Как эти байты интерпретируются, зависит от программы, которую вы используете (например, заботитесь о спецификации или нет), когда открываете файл.
Обратитесь к этой ссылке форума MSDN: Почему printf может отображать символы не ASCII, если используется локаль «C»?