This question already has answers here:
Is it possible to cout an EM DASH on Linux and Windows? [duplicate]

(2个答案)


3年前关闭。




一个简单的问题:我正在为一个类用C++(但主要是C风格)编写一个聊天室程序,并且试图在输出窗口中打印“#help —显示命令列表...”。 。虽然我可以使用两个连字符(-)来达到大致相同的效果,但我宁愿使用破折号(-)。 printf()似乎不支持打印破折号。取而代之的是,尽管直接在提示符中输入破折号也可以,但控制台只是在其位置打印出了字符ù。

如何显示这个简单的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,并在适当的地方使用CodePage来使用 GetConsoleOutputCP 返回的值。如果您使用的字符> 0x80,则这里(翻译)可能会出现问题

首先,编译器会警告您:该文件包含一个无法在当前代码页(数字)中表示的字符。以Unicode格式保存文件以防止数据丢失。 (C4819)。但即使您以Unicode格式保存源文件,也可以执行以下操作:
wprintf(L"ù"); // no warning
printf("ù"); //warning C4566

因为L"ù"保存为宽字符字符串(按原样)在二进制文件中-此处一切正常,没有任何问题和警告。但是"ù"保存为字符字符串(单字节字符串)。编译器需要将二进制文件中的宽字符串“ù”从源文件转换为多字节字符串(.obj文件,链接器将从中创建pe)。和 WideCharToMultiByte 与CP_ACP一起用于编译器(当前系统默认的Windows ANSI代码页。)

那么,如果您说致电printf("ù");会怎样?
  • Unicode字符串“ù”将转换为多字节WideCharToMultiByte(CP_ACP, ),这将在编译时进行。生成的多字节字符串将保存在二进制文件
  • 控制台它运行时将您的多字节字符串转换为
    宽字符由MultiByteToWideChar(GetConsoleOutputCP(), ..)
    打印此字符串

  • 因此您获得了2次转化:unicode -> CP_ACP -> multi-byte -> GetConsoleOutputCP() -> unicode
    默认情况下,即使您在编译它的计算机上运行程序,GetConsoleOutputCP() == CP_OEMCP != CP_ACP也是如此。 (尤其是在另一台具有另一个CP_OEMCP的计算机上)

    转换不兼容的问题-使用了不同的代码页。但是,即使将控制台代码页更改为CP_ACP,转换也可能会错误地翻译某些字符。

    关于CRT api wprintf-接下来是这种情况:
    wprintf首先使用内部locale将给定的字符串从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。

    关于c++ - 使用printf将短划线打印到控制台窗口? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46226592/

    10-11 22:39
    查看更多