Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么printf可以显示非ASCII字符;";是否使用区域设置? 注:我在微软Visual C++ 2008中(在2005 +上可能是相同的),请求实现定义的行为。操作系统:Win7的简体中文安装_C++_Visual C++_Console_Locale_Mbcs - Fatal编程技术网

为什么printf可以显示非ASCII字符;";是否使用区域设置? 注:我在微软Visual C++ 2008中(在2005 +上可能是相同的),请求实现定义的行为。操作系统:Win7的简体中文安装

为什么printf可以显示非ASCII字符;";是否使用区域设置? 注:我在微软Visual C++ 2008中(在2005 +上可能是相同的),请求实现定义的行为。操作系统:Win7的简体中文安装,c++,visual-c++,console,locale,mbcs,C++,Visual C++,Console,Locale,Mbcs,当我执行非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 ("%s\n", setlocale(LC_ALL, NUL

当我执行非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 ("%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”语言环境的代码点范围内,即
0x0~0x7F

问题:

为什么它仍然可以在“C”语言环境中正确显示字符?因此我猜测语言环境与
printf
没有关系?但是,我要问,为什么它在更改为
“English”
语言环境时不能再显示,这也不同于936?有趣吗

编辑:


我将标准输出重定向到一个文件并进行了一些测试。它显示,无论设置了什么语言环境,都是正确的字符
”中“
保存在文件中。这表明
setlocale()
连接到console显示字符的方式,这与我对其工作原理的理解相矛盾:
printf
将字节/代码点放入console的输入缓冲区,console使用自己的代码页解释这些字节(chcp
返回的内容).936是一个相当复杂的代码页,它允许2个符号字符(类似于UTF-8)。例如西里尔字母(866)-不允许两个字节字符,其行为将与“英语”相同

因此,当您使用默认(936)代码页时,它知道如何处理2符号字符,而“English”只处理
0x0~0x7f

我还要回答为什么
wprintf(L)中“”
失败。控制台应用程序和Windows窗口应用程序之间有很大区别,它们使用不同的代码页 以下是控制台和windows之间的匹配:

DOS   |   Windows
------+----------
850   |  1252
936   | 54936
866   |  1251

因此,如果您希望在控制台中看到正确的符号首先使用
WideCharToMultiByte
,这提供了预期的转换,以允许控制台在936中工作,那么C语言环境完全按照给定的方式打印字符串的事实并不令人惊讶。这正是我所期望的。令人惊讶的是,英语语言环境会做一些事情不一样

根据do,区域设置对printf的唯一影响是确定数值的基数字符(即小数点)

我怀疑这可能是微软编译器中的一个bug,或者至少是未记录的行为

值得一提的是,在我的编译器(Borland)上,区域设置对这些字符串的输出没有影响。但它确实影响基数。

OK。对于默认的“C”“区域设置,CRT假定传递给
printf
的字符不需要任何转换。这是有原因的,因为ASCII字符几乎总是属于执行系统的基本字符集(在不同的Windows代码页之间共享)。当切换到“English”时,它假定输入在代码页1252中编码,因此尝试执行从“English”到“Chinese”的转换,这是控制台使用的语言环境。但是CRT就是找不到字符
在代码页1252中。这就是为什么它会输出一个问号

当重定向到某个文件时,CRT知道该文件,不会进行转换,因为不再使用控制台代码页。它只是按原样通过字节。如何解释这些字节取决于打开文件时使用的程序(例如,是否关心BOM)


请参阅此MSDN论坛链接:

我认为您系统上的C语言环境是Unicode(UTF-8或类似的),而英语语言环境包括ASCII。我认为不是。如何使用UTF-8对GB2312编码字符进行解码?顺便说一句,在微软的世界里,我认为英语语言环境(ANSI)是他们调用的“C”语言环境(ASCII)的超集。字符编码之间的转换是可能的。它不能是Unicode(至少是UTF-16),就像
wprintf(L)一样中")未显示正确的字符。在VC2008(可能是2005+)中,宽字符编码为UCS2/UTF-16。但我同意您可能存在转换。我将更新我的问题。谢谢。我可以理解为什么
“English”
区域设置不起作用。但我主要关心的是
“C”
区域设置为什么起作用?
“C“
locale不应该是任何UTF或936,希望如此。为什么“英语”不起作用?@EricZ-在回答之前,UTF不能作为控制台输出。好的,想象一下printfimpl中的以下伪代码:`if(consumer_two_bytes(*str)){console_put2(*str,*(str+1));}”
.So
NULL`被映射到936处理程序,936处理程序知道存在必须作为单个字符处理的2字节字符(与UTF-8使用的方式类似)。但是对于“English”处理程序,没有检查2字节字符。ll实际上不是NULL。它是默认的“C”语言环境。因此,它应该被视为与“English”相同的方式,因为两者都不能处理中文字符。事实上,当语言环境为“英语”时,printf会以某种方式将代码点转换为其他内容,这会导致控制台解码错误。我怀疑这是一个错误,因为printf应该做的就是将字节放入控制台缓冲区。由于控制台代码页已经与char*文本的编码方式相同,setlocale不应该对printf有任何影响。只是找不到任何正式的文档/错误报告。@EricZ from doc:“该函数还可以通过传递NULL作为区域设置的值来检索当前区域设置的名称。”这意味着NULL不是“English”(850),但您设置为本地Windows版本(显然是936)。因此printf中没有错误,它是有文档记录的行为。引用的语句是正确的,但您的结论是错误的,很遗憾;)经过