使用printf将em-dash打印到控制台窗口?

一个简单的问题:我正在用C ++编写一个聊天室程序(但主要是C风格),我试图在输出窗口中打印“#help – 显示一个命令列表…” 。 虽然我可以使用两个连字符( – )来达到大致相同的效果,但我宁愿使用em-dash( – )。 然而, printf()似乎不支持打印em-dashes。 相反,控制台只是在其位置上打印出字符ù,尽pipe直接在提示符中inputem-dashes可以正常工作。

我如何得到这个简单的Unicode字符显示?

看看Windows的ALT键代码,我觉得有趣的是,alt + 0151是“ – ”,而alt + 151是“ù”。 这是关系到我的问题,还是一个简单的巧合?

windows是unicode(UTF-16)系统。 控制台unicode以及。 如果你想打印unicode文本 – 你需要(这是最有效的)使用WriteConsoleW

 BOOL PrintString(PCWSTR psz) { DWORD n; return WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), psz, (ULONG)wcslen(psz), &n, 0); } PrintString(L"—"); 

在这种情况下,你的二进制文件将是宽字符 (2字节0x2014 )和控制台打印它是。

如果为输出控制台调用了ansi(多字节)函数 – 比如WriteConsoleAWriteFile – 控制台,首先通过MultiByteToWideChar将多字节字符串转换为unicode,并将代码页使用由GetConsoleOutputCP返回的GetConsoleOutputCP 。 如果使用字符> 0x80,这里(翻译)可能会出现问题

首先编译器会给你警告: 文件中包含一个不能在当前代码页(数字)中表示的字符。 以Unicode格式保存文件以防止数据丢失。C4819 )。 但即使以Unicode格式保存源文件,也可以在下一步:

 wprintf(L"ù"); // no warning printf("ù"); //warning C4566 

因为L"ù"二进制文件中保存为宽字符串 (如此) – 在这里一切正常,没有任何问题和警告。 但"ù"被保存为char字符串 (单字节字符串)。 编译器需要将源文件中的宽字符串 “ù”转换为二进制的多字节字符串.obj文件,链接器创建的文件比)。 和编译器使用此WideCharToMultiByteCP_ACP当前系统默认的Windows ANSI代码页)。

所以如果你说printf("ù");

  1. unicode字符串“ù”将被转换为多字节WideCharToMultiByte(CP_ACP, ) ,这将在编译时 。 产生的多字节字符串将被保存在二进制文件中
  2. 运行的控制台通过MultiByteToWideChar(GetConsoleOutputCP(), ..)将您的多字节字符串转换为宽字符,并打印此字符串

所以你有2个转换: unicode -> CP_ACP -> multi-byte -> GetConsoleOutputCP() -> unicode

即使您在编译它的计算机上运行程序,默认情况下为GetConsoleOutputCP() == CP_OEMCP != CP_ACP 。 (在另一台计算机上使用另一个CP_OEMCP

不兼容的转换问题 – 使用不同的代码页。 但即使您将控制台代码页更改为您的CP_ACP – 无论如何转换可能会错误地翻译一些字符。

和关于CRT api wprintf – 这里的情况是下一个:

wprintf首先使用内部当前语言环境将给定的字符串从unicode转换为多字节(注意独立于crt语言环境,与控制台语言环境不同)。 然后用多字节字符串调用WriteFile 。 控制台将此多字节字符串转换为Unicode

unicode -> current_crt_locale -> multi-byte -> GetConsoleOutputCP() -> unicode

所以为了使用wprintf我们需要首先将当前的crt语言环境设置为GetConsoleOutputCP()

 char sz[16]; sprintf(sz, ".%u", GetConsoleOutputCP()); setlocale(LC_ALL, sz); wprintf(L"—"); 

但无论如何,在这里我查看(在我的比赛) -在屏幕上,而不是 。 所以会-—如果调用PrintString(L"—"); (它使用了WriteConsoleW )。

所以只有可靠的方式打印任何unicode字符(由Windows支持) – 使用WriteConsole W api。

通过评论后,我发现eryksun的解决方案是最简单的(…和最容易理解):

 #include <stdio.h> #include <io.h> #include <fcntl.h> int main() { //other stuff _setmode(_fileno(stdout), _O_U16TEXT); wprintf(L"#help — display a list of commands..."); 

可移植性不是我的问题,这解决了我最初的问题 – 没有更多的 – 我的心爱的电子短跑正在展示。

我承认这个问题基本上是由sata300.de链接的问题的重复。 尽管如此,用printf代替了cout ,并且在相关信息的地方不必要的ramblings。