为什么 printf 在使用区域设置时可以显示非 ASCII 字符"C"?
Why printf can display non-ASCII characters when "C" locale is used?
注意:我问的是在Microsoft Visual c++ 2008上实现定义的行为(可能在2005+上相同)。操作系统:简体中文安装Win7.
当我执行非ascii I/O w/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 ("%sn", setlocale(LC_ALL, NULL));
printf ("中n");
printf ("%sn", 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)。例如Cyrillic(866) -不允许双字节字符,其行为将与"English"相同。
因此,当您使用默认(936)代码页时,它知道如何处理2符号字符,而"English"仅处理0x0 ~ 0x7f
。
让我也回答为什么wprintf(L"中")
失败。控制台应用程序和windows窗口应用程序有很大的区别,它们使用不同的代码页下面是控制台和窗口之间的匹配:
DOS | Windows
------+----------
850 | 1252
936 | 54936
866 | 1251
所以如果你想在控制台看到正确的符号首先使用WideCharToMultiByte
-这提供了预期的转换,以允许控制台工作在936
C语言环境完全按照给定的方式打印出字符串这一事实并不奇怪。这就是我所期望的。令人惊讶的是,英语语言环境会做一些不同的事情。
根据MSDN上的语言环境文档,语言环境对printf
的唯一影响应该是确定数字值的基数字符(即小数点)。
我怀疑这可能是微软编译器的一个bug。或者至少它是未记录的行为。
值得注意的是,在我的编译器(Borland)上,区域设置对这些字符串的输出没有影响。但是它确实影响基数
OK。对于默认的"C"区域设置,CRT假定传递给printf
的字符不需要任何转换。这是有原因的,因为ASCII字符几乎总是属于执行系统的基本字符集(在不同的Windows代码页之间共享)。当切换到"English"时,它假设输入是在代码页1252中编码的,因此尝试执行从"English"到"Chinese"的转换,这是控制台使用的区域设置。但是CRT无法在代码页1252中找到字符中
。这就是为什么它输出一个问号。
当重定向到一个文件时,CRT知道它并且不会进行转换,因为不再使用控制台代码页。它只是按原样传递字节。如何解释这些字节取决于您使用的程序(例如。(是否关心BOM),当您打开文件时
参考这个MSDN论坛链接:为什么当使用"C"区域设置时,printf可以显示非ascii字符?
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 字符串-C++后显示的随机字符
- 继承期间显示未知行为的子类
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- 我的程序将 26 个字母转换为 ascII 没有显示正确答案
- 我写的 ASCII 到二进制转换器C++向后显示二进制,如何使其正确显示?
- 当我尝试将范围值存储为 8 位的固定宽度整数时,它向我显示一些其他值 [ASCII]
- 如何在不将其转换为 ASCII 字符的情况下显示 QByteArray 的十六进制值
- 控制台输出显示ASCII值,而不是数字的预期数字
- 尝试显示 ASCII 字符串,但它被截断
- C++ 字符仅显示 ASCII 值
- 如何在QTextEdit中显示扩展的ascii字符
- ASCII 和二进制 - 按原样显示,但读取返回垃圾
- 如何使用 ASCII 代码在输出屏幕上显示图像C++
- 尝试在C++中制作 ASCII 表,无法使"special characters"正确显示
- c++windows10中的ascii心脏不显示
- 如何用十六进制而不是ASCII符号显示实际值?
- 为什么 printf 在使用区域设置时可以显示非 ASCII 字符"C"?
- 十六进制转储实用程序c++显示十六进制和Ascii