【问题标题】:How to display accented chars on the console window, that work for all compiler?如何在控制台窗口上显示重音字符,适用于所有编译器?
【发布时间】:2017-05-28 05:21:55
【问题描述】:

我做了一个程序,在运行过程中在屏幕上打印公交车站的名称,这些名称通常包含重音字符。我做了一个对我和我的朋友在 Visual Studio '13 和 '15 上都很好用的解决方案,但我纠正程序的老师回答说它对他不起作用。文件NULL 位于包含代码的文件夹中。 我用这个:

setlocale(LC_ALL, "");

system("chcp 1250 > NULL");

printf("Mária Terézia körút\n");

我的问题:如何让程序在每个编译器和操作系统上显示重音字符?

【问题讨论】:

  • 这是一个棘手的领域,但chcp 不是大多数基于 Unix 的系统上的程序,因此对于“每个编译器和操作系统”来说,这不是一个初学者。您可能应该澄清“每个编译器和操作系统”的含义。简单的事实是,您可能无法使其适用于每个 编译器和操作系统——周围有太多过时的仍在使用并且不支持不同的代码集。幸运的是,它们大多没有广泛用于服务器或台式机/笔记本电脑系统。您需要知道终端(控制台)使用的代码集,并确保区域设置正确。
  • 嗯,在答案中,老师建议我在 Win 7/8/10 上测试,但我在发送之前已经在 7 和 10 上进行了测试。如果我可以记录如果它不工作必须更改的内容,这也是一个解决方案。在 Code::Blocks 上,它既不为我显示字符(GNU 编译器),所以我在想他是否没有使用 Visual Studio,尽管它也在学校用于考试。
  • 好的——这是对“所有编译器和操作系统”的不同解释,与我的预期不同。 (我将 macOS、Linux、BSD、Solaris、AIX、HP-UX 归为“所有编译器和 o/s”标题下的操作系统。)我无法为您提供进一步的帮助 — 除了通过意外或必要时(有人让我可以使用 Windows 机器;我自己或工作中没有 Windows 机器)。
  • 好的,还是谢谢你。
  • 所有编译器上没有任何作用。即使在理论上,此特定功能也不适用于所有符合标准的编译器。该标准不要求任何特定字符的字符可以正确显示在控制台上,也不要求您的程序使用所需的字符集需要做什么。

标签: c display non-ascii-characters


【解决方案1】:

不幸的是,在所有编译器上没有任何东西可以工作,但是通过一些#if 块,我们可以非常接近。据报道,这样的代码在 tdm-gcc 上会失败。

在 C 中执行此操作的标准方法是使用标准库打印宽字符串。不幸的是,如果没有一些额外的初始化,这不适用于 MSVC 运行时。如果这样做,您将无法在同一程序中在wprintf() 等宽字符函数和printf() 等窄字符函数之间来回切换。

#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>

/* This has been reported not to autodetect correctly on tdm-gcc. */
#ifndef MS_STDLIB_BUGS // Allow overriding the autodetection.
#  if ( _WIN32 || _WIN64 )
#    define MS_STDLIB_BUGS 1
#  else
#    define MS_STDLIB_BUGS 0
#  endif
#endif

#if MS_STDLIB_BUGS
#  include <io.h>
#  include <fcntl.h>
#endif

void init_locale(void)
// Does magic so that wprintf() can work.
{
  // Constant for fwide().
  static const int wide_oriented = 1;

#if MS_STDLIB_BUGS
  // Windows needs a little non-standard magic.
  static const char locale_name[] = ".1200";
  _setmode( _fileno(stdout), _O_WTEXT );
#else
  // The correct locale name may vary by OS, e.g., "en_US.utf8".
  static const char locale_name[] = "";
#endif

  setlocale( LC_ALL, locale_name );
  fwide( stdout, wide_oriented );
}

int main(void)
{
  init_locale();
  wprintf(L"Mária Terézia körút\n");
  return EXIT_SUCCESS;
}

为了与所有最近的编译器兼容,您必须将其保存为带有 BOM 的 UTF-8。 (VS 2017 之前的 MSVC 版本在没有 BOM 的情况下无法读取 UTF-8,而 clang 无法读取除 UTF-8 之外的任何内容。)

为了在控制台上阅读文本,您必须将字体设置为等宽 Unicode 字体,例如 Lucida Console。

在 Linux 上,确保您的语言环境变量设置正确,并且它们与您的终端设置相匹配。

另一种方法是将控制台设置为 UTF-8(在 Windows 上,此命令是 chcp 65001。在 Linux 上,它是 export LANG=en_US.utf8 或来自 locale -a 的适当等效项,并且可能默认设置.) 然后printf(u8"Mária Terézia körút\n");。请注意:UTF-8 在 Windows 上是二等公民。

【讨论】:

  • 非常感谢您的回答。该代码对我不起作用,有 1 个错误:_0_WTEXT 未声明。也许缺少标题?
  • @Urudin 也许您应该复制和粘贴代码,而不是尝试重新键入它。那里有一个 O,而不是 0。
  • 我已经把它复制到编译器,只是重新输入评论:)
  • @Urudin 哪个编译器和操作系统?尝试从 VS Native Tools 提示符运行。
  • Windows 7 Pro,我在 Code::Blocks(GNU) 和 Visual Studio 上都试过了。他们给出了不同的错误。 Code::Blocks 给出了我之前提到的那个,VS 错误是:LNK2019 unresolved external symbol _main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) LNK1120 1 unresolved external Both found in the first line.
【解决方案2】:

为了与 Web(W3C、IETF)和 *nix 系统(Linux;BSD、Android、OSX、GCC、CLang)兼容,请使用不带 BOM 的 UTF-8(按其设计)。

为了与仍在为 unicode 迁移而苦苦挣扎的遗留专有系统兼容,请使用带有 BOM 的 UT-8。或者承认他们还没有准备好使用 unicode 并使用传统的专有 8 位编码(您有一天需要迁移到 UTF-8,所以这只是添加需要修复的代码)。

提示:对于 BOM,UTF-8 与 ASCII 不兼容,因此无法轻松地从 8 位编码迁移到 Unicode。

【讨论】:

    【解决方案3】:

    我设法想出了一个似乎可以解决问题的简单解决方案。使用它可以使匈牙利语的重音字符在 Win7 和 Win10 以及 VS '13 '15 和 Code::Blocks 上工作。

    #include <locale.h>
    #if defined(WIN32) || defined(_WIN32)
    #include <windows.h>
    #endif
    

    主要:

    setlocale(LC_ALL, "");
    #if defined(WIN32) || defined(_WIN32)
    SetConsoleCP(1250); SetConsoleOutputCP(1250);
    #endif
    

    【讨论】:

    • 1250 是一个过时的单字节字符集,几乎没人使用,2017 年也不应该使用。它可能会或可能不会在短期内满足您的需求,但如果您想从长远来看,你想学习有关 Unicode 的东西,保持相关性。 Here 是一个好的开始。作为对公共问题的公开回答,这应该被否决,因为它为毫无戒心的新手提供了非常糟糕的建议。
    • 好吧,这肯定不是问题的完整解决方案,解决了我的问题,并使用匈牙利字母处理 Vstudio 和 Code::Blocks。我已经让我的朋友测试它,在 5 Windows PC 上运行良好,所以我在描述中写了它在哪里工作。但我忘了补充,我只测试了匈牙利字母,我现在纠正这个错误。
    • 这也不适用于 Windows 以外的任何操作系统,而具有 wprintf() 和宽字符串的解决方案理论上适用于任何符合标准的编译器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 2012-04-21
    • 2011-12-09
    • 1970-01-01
    相关资源
    最近更新 更多