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

时间:2017-09-14 19:08:43

标签: c++ c windows visual-studio windows-console

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

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

查看Windows alt键代码,我觉得有趣的是alt + 0151是“ - ”而alt + 151是“ù”。这与我的问题有关,还是简单的巧合?

2 个答案:

答案 0 :(得分:0)

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 比)。和#em> CP_ACP (当前系统默认的Windows ANSI代码页。

的编译器用于此WideCharToMultiByte

如果你说拨打printf("ù");会怎么样?

  1. unicode string“ù”将转换为多字节 WideCharToMultiByte(CP_ACP, )这将是编译时。结果多字节字符串将保存在二进制文件
  2. 控制台运行时多字节字符串转换为 MultiByteToWideChar(GetConsoleOutputCP(), ..)unicode -> CP_ACP -> multi-byte -> GetConsoleOutputCP() -> unicode 打印此字符串
  3. 所以你获得了2次转换:GetConsoleOutputCP() == CP_OEMCP != CP_ACP

    默认情况下CP_OEMCP,即使您在编译它的计算机上运行程序也是如此。 (在另一台计算机上使用另一台CP_ACP特别是)

    不兼容转换中的问题 - 使用了不同的代码页。但即使您将控制台代码页更改为wprintf - 转换,无论如何都可能会错误地转换某些字符。

    和关于 CRT api wprintf - 下面是这种情况:

    WriteFile首先使用内部当前locale将给定字符串从unicode转换为多字节(并注意 crt 区域设置独立且与控制台不同区域设置)。然后使用多字节字符串调用unicode -> current_crt_locale -> multi-byte -> GetConsoleOutputCP() -> unicode。 console将这个多字节字符串转换回unicode

    wprintf

    为了使用GetConsoleOutputCP(),我们需要先将当前的crt语言环境设置为char sz[16]; sprintf(sz, ".%u", GetConsoleOutputCP()); setlocale(LC_ALL, sz); wprintf(L"—");

    -

    但无论如何,我在屏幕上上查看(在我的比赛中)-—PrintString(L"—");。如果在此之后调用WriteConsoleW(使用 public void tryPost() { RequestQueue queue = Volley.newRequestQueue(this); String serverUrl = "http://10.0.2.2:3000/tasks"; StringRequest stringRequest = new StringRequest(Request.Method.POST, serverUrl, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("TAG", "response = "+ response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.d("TAG", "Error = "+ error); } }) { // @Override public Map<String, String> getHeaders() { HashMap<String, String> headers = new HashMap<>(); headers.put("Accept", "application/json"); headers.put("Content-Type", "application/json"); return headers; } //// @Override public Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); params.put("userId","sargent"); params.put("password","1234567"); return params; //return the parameters } }; // Add the request to the RequestQueue. queue.add(stringRequest); } ),那么10.1也是如此。

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

答案 1 :(得分:0)

在完成评论后,我发现eryksun的解决方案是最简单的(......也是最容易理解的):

{
  "manifest_version": 2,

  "name": "chrome extension",
  "description": "This extension will used to simplify the project",
  "version": "1.0",

  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": [
    "http://example.com/*",
    "activeTab"
  ]
}

便携性不是我的担忧,这解决了我最初的问题 - 不再ù-我心爱的em-dash正在展出。

我承认这个问题基本上是the one linked by sata300.de的副本。虽然#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..."); 代替printf,但有相关信息的地方也有不必要的谣言。