在32位Windows上的Visual Studio 2005中,为什么我的控制台不会显示128到255之间的字符?
例如:
cout << "¿" << endl; //inverted question mark
输出:
┐
Press any key to continue . . .
答案 0 :(得分:13)
Windows 控制台窗口是纯Unicode。它的缓冲区将文本存储为UCS-2 Unicode(每个字符16位,基本上类似于原始Unicode,对现代21位Unicode的基本多语言平面的限制)。因此,控制台窗口可以显示几乎所有类型的文本。
但是,对于每个字符的单字节(也可能是某些可变长度编码),i / o Windows会自动转换为控制台窗口的活动代码页。如果控制台窗口是[cmd.exe]实例,则可以通过 chcp
命令检查该实例,更改代码页的缩写。像这样:
C:\test> chcp Active code page: 850 C:\test> _
代码页850是基于原始IBM PC英文代码页437的编码。对于至少挪威PC的控制台窗口,850是默认的(尽管精明的挪威人可能将其更改为865)。但是,这些都不是您应该使用的代码页。
最初的IBM PC代码页(字符编码)称为 OEM ,这是一个毫无意义的缩写,原始设备制造商。它具有适合原始PC文本模式屏幕的漂亮的线条绘制字符。更一般地,OEM意味着控制台窗口的默认代码页,其中代码页437只是原始代码页:它可以被配置,例如,每个窗口通过chcp
。
当Microsoft创建16位Windows时,他们选择Windows中已知的另一种编码 ANSI 。最初的一个是 ISO Latin-1 的扩展,很长一段时间是互联网上的默认值(但是,目前还不清楚哪个是第一个:微软参与了标准化)。此原始ANSI现在称为 Windows ANSI Western 。
ANSI是几乎所有其他Windows使用的非Unicode代码页。控制台窗口使用OEM。记事本,其他编辑器等使用ANSI。
然后,当微软制造Windows 32位时,他们采用了拉丁语-1的16位扩展名为 Unicode 。 Microsoft是Unicode Consortium的原始创始成员。并且基本API(包括控制台窗口,文件系统等)被重写为使用Unicode。为了向后兼容,有一个转换层可以在控制台窗口的OEM和Unicode之间进行转换,在ANSI和Unicode之间转换其他功能。例如,MessageBoxA
是基于Unicode的MessageBoxW
的ANSI包装器。
实际结果是,在Windows中,您的C ++源代码通常使用ANSI编码,而控制台窗口则采用OEM。例如,使
cout << "I like Norwegian blåbærsyltetøy!" << endl;
生成纯gobbledegook ...您可以使用基于Unicode的控制台窗口API将Unicode直接输出到控制台窗口,避免翻译,但这很尴尬。
请注意,使用wcout
代替cout
无济于事:按设计wcout
只需将宽字符串向下转换为程序的窄字符集,即可丢弃信息。令人难以置信的是,C ++标准库提供了相当大的非常复杂的功能,这些功能毫无意义(因为这些转换可能只是由cout
支持)。但它就是这样,毫无意义。可能这是一些政治性的妥协,但无论如何,wcout
做不帮助,即使它在某种程度上有意义,那么它“应该”在逻辑上帮助这个。
那么挪威新手程序员如何得到如“blåbærsyltetøy”出现了?
好吧,只需将活动代码页更改为ANSI即可。由于在大多数西方国家的PC上,ANSI是代码页1252,您可以通过
为给定的命令解释器实例执行此操作C:\test> chcp 1252 Active code page: 1252 C:\test> _
现在的旧DOS程序,例如[edit.com](仍然存在于Windows XP中!)会产生一些gobbledegook,因为原始的PC字符集线条绘制字符在ANSI中没有,并且因为国家字符在ANSI中有不同的代码。但嘿,谁使用旧的DOS程序?不是我!
如果您希望将其作为更永久的代码页,则必须通过未记录的注册表项更改控制台窗口的配置:
HKEY_LOCAL_MACHINE \ SYSTEM \ CURRENTCONTROLSET \控制\ NLS \代码页
在此密钥中,将OEMCP
的值更改为1252,然后重新启动。
与chcp
一样,或者代码页的其他更改为1252,使旧的DOS程序呈现gobbledegook,但使C ++程序或其他现代控制台程序正常工作。
因为您在控制台窗口中具有与Windows其余部分相同的字符编码。
答案 1 :(得分:3)
当您打印ASCII字符串时,Windows会根据当前代码页在内部将其转换为UNICODE。还有一个从UNICODE到CRT完成的“ASCII”的翻译。以下是有效的。
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <iostream>
void
__cdecl
main(int ac, char **av)
{
_setmode(_fileno(stdout), _O_U16TEXT);
std::wcout << L"\u00BF";
}
答案 2 :(得分:2)
因为Win32控制台使用code page 437(也就是OEM字体)来呈现字符,而其余大多数Windows使用Windows-1252来表示单字节字符代码。
字符“¿”是Unicode字符INVERTED QUESTION MARK,它在Unicode,ISO 8859-1和Windows-1252中具有代码点0xBF(十进制191)。 CP437中的代码点0xBF对应于字符“┐”,即BOX图片LIGHT DOWN AND LEFT(代码点U + 2510)。
只要您使用的是Windows控制台,就可以只显示CP437中的字符而不显示其他字符。如果要显示其他Unicode字符,则需要使用其他环境。
答案 3 :(得分:0)
可能使用基本的ascii字符集实现。 Microsoft程序员在创建控制台时没有添加utf-8功能。只是一个猜测,因为我不是一个参与创建控制台的Microsoft程序员。