如何在所有平台上使用C ++程序显示重音字符?

时间:2015-03-18 01:48:07

标签: c++ linux windows utf-8 locale

我正在尝试将C ++ 11程序从Windows移植到Linux(GCC-4.9)。 最初,我只是在程序中设置了语言环境

  

setlocale(LC_ALL,“”);

但是,它在Linux上显示缺少的字符(最新版本的Linux Mint)。然后我继续以UTF-8格式保存我的所有源文件,这解决了linux下的问题,但现在所有的字符都搞砸了。

如果有帮助,语言是法语。 有没有办法在两个平台下正确显示文本而不会有太多麻烦?

我很感激帮助,谢谢。

void EcranBienvenue()
{
    char coinHG = (char)201;
    char coinHD = (char)187;
    char coinBG = (char)200;
    char coinBD = (char)188;
    char ligneH = (char)205;
    char ligneV = (char)186;
#ifdef _WIN32
    system("cls");
#elif defined __linux__
        system("clear");
#else
        cout << string(20,'\n');
#endif
    setlocale(LC_ALL, "C");
    cout << coinHG;
    for (int i = 0; i < 48; i++)
        cout << ligneH;
    cout << coinHD << endl;
    cout << ligneV << "                                                " << ligneV << endl;
    cout << ligneV << "     Les productions                 inc        " << ligneV << endl;
    cout << ligneV << "                                                " << ligneV << endl;
    cout << ligneV << "     Système de gestion des abonnements         " << ligneV << endl;
    cout << ligneV << "                                                " << ligneV << endl;
    cout << coinBG;
    for (int i = 0; i < 48; i++)
        cout << ligneH;
    cout << coinBD << endl;
    setlocale(LC_ALL, "");

}

边界在Linux上不起作用是正常的。 但是,三行文本将在终端上准确显示。

在Windows上,“è”将是一个不正确的角色。

Système de gestion des abonnements 

2 个答案:

答案 0 :(得分:2)

C ++没有为(窄)字符串定义任何编码,Windows使用CP-1252而Linux使用UTF-8。使用std::wstringstd::wcout

答案 1 :(得分:1)

有很多不同的方法来做这种事情,但肯定有一些不好的方法。我强烈建议避免一些事情:

  • 不要更改全局C或C ++语言环境。在大多数情况下,完全避免使用语言环境。
  • 不要使用wchar_t(除了在跨平台实现的隐藏的内部API之外,仅将wchar_t用于Windows实现)。
  • 除非绝对必要,否则不要使用旧版编码。 (遗留编码是除UTF-8,UTF-32和UTF-16之外的所有内容。

您遇到的问题是因为您使用错误的编码在接口之间传递文本数据。

例如:

Système de gestion des abonnements

这是因为您将UTF-8编码的文本传递给期望使用(可能)Microsoft的代码页850(您的控制台的OEM代码页)编码的数据的接口。

您需要知道接口所需的编码才能使用它。您还需要知道数据使用的编码方式。为此,您应该选择在代码中使用的一致编码,并在接口边界根据需要将其他数据转换为该编码。我相信UTF-8是跨平台代码的最佳选择。


由于MSVC实现标准C和C ++ IO工具的缺点,您可能最好使用本机Win32实现实现自己的IO API。

Here's一个关于在Windows上实现输出功能的页面。

本文中实现的print函数采用wchar_t输入。这是将UTF-8转换为UTF-16 / wchar_t的一种方法:

#include <codecvt>
#include <locale>

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;

std::string str = "Système de gestion des abonnements";
UPrint(convert.from_bytes().c_str());

此外,您可以实现正确处理写入Windows控制台的streambuf并用std::cout替换它中的streambuf,以便打印到cout然后正确打印到控制台。记得在退出之前恢复原始的streambuf,以便cout的破坏能够成功。您可以使用RAII类型对象处理设置流缓冲区并稍后将其切换回来。

这样的程序可能看起来像:

int main() {
  Set_utf8_safe_streambuf buffer_swapper(std::cout); // on windows swaps cout's streambuf with one that can print UTF-8 to the console, does nothing on other platforms

  std::cout << "Système de gestion des abonnements" << '\n'; // utf-8 data
}

这是一个answer,其中包含有关实施和交换streambuf的一些细节。