使用'\ uxxxx'格式定义的字符显示错误的字符

时间:2013-03-21 21:56:45

标签: c++ unicode character-encoding

我正在使用Dev C ++,Windows 7。

我正在尝试使用以下方法打印出非ascii字符:

char a='\uwxyz';

例如:

#include <locale.h>
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <conio.h>
#include <stdio.h>

using namespace std;

int main()
{
    setlocale(LC_ALL,"en_US.UTF-8");
    char a='\u0041'; //Should display 'A'
    cout<<a<<endl;
    a='\u2639'; //Should display '☹'
    cout<<a<<endl;
    system("PAUSE");
}

在此示例中,大写A正确显示。使用wxDev,☹字符只显示任何内容。使用Dev(我需要用于最终程序),我会得到一个扩展的ascii字符(它是一个类似于symbol的符号,但有多个符号看起来像那样,我无法分辨它是什么)。

在Dev和wxDev中,☹显示为?。

我在初步搜索了如何正确显示unicode字符之后添加了setlocale,但我还没有找到任何解决这个问题的方法。

我无法使用其他编译器或修改系统设置来使其工作。 (是的,这是一个学校项目。不,项目不需要特殊字符;我只是想让它看起来更好。)如果不修改这些设置就无法工作,那也是有用的信息。

提前感谢您的帮助。

编辑:使用Dev,而不是wxDev,

char a='\u0041'; //should be A
cout<<a;

我收到错误:\ u0041不是有效的通用字符

如果我使用wchar_t作为数据类型:

wchar_t a = '\u2639';
cout<<a<<endl;

输出为39097。

1 个答案:

答案 0 :(得分:3)

通用字符名称(UCN)是一种向编译器传达要表示的字符的方法。只要您可以将基本源字符添加到编译器中,那么每个编译器都将看到相同的UCN,因此会看到您表示相同的字符。

这与在字面上直接写字符相反:

char a = '☹';

由于编译器只需要支持基本源字符,因此编译器甚至无法处理此代码。它实际看到的内容取决于编译器使用的源编码。一个编译器可能会在另一个编译器看到

时看到您想要的字符
char a = 'Â☐¹';

但是,仅仅因为UCN能够为编译器指定字符并不意味着:

  • 编译器的执行字符集包含该字符或
  • 数据类型char可以表示该字符值

在您的情况下,主要问题是执行字符集是Windows的代码页(可能是CP1252)之一,它没有字符'☹'。因此,当编译器将字符“☹”转换为执行字符集时,转换会产生“?”而不是你想要的。

我的编译器的执行字符集确实包含字符'☹',但它碰巧有一个多字节表示,所以我的编译器说:

error: character too large for enclosing character literal type
    char a = '☹';
             ^

要真正理解这个主题,您需要了解编码,字符集,它们如何进入翻译的C ++阶段,以及它与编译器处理字符和字符串文字的关系。此外,语言环境实际上与此无关; locales处理运行时行为,而您的问题完全取决于编译器编译时的编码处理。


在以下任何地方使用UTF-8的平台上:

#include <iostream>

int main() {
    std::cout << "☹\n";
}

请注意,上面使用字符串文字而不是字符文字,以便字符可以扩展为其多字节表示。

不幸的是,Windows不支持这种方式的Unicode。在Windows上它更复杂:

#include <Windows.h>
#include <cwchar>

int main() {
    wchar_t const *a = L"\u2639\n";
    DWORD numOfCharsWritten;
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), a, wcslen(a), &numOfCharsWritten, NULL);
}

不幸的是,即使上面的代码也不太可能显示您想要的内容,因为Windows上的控制台通常没有配置为能够显示Unicode字符“☹”。相反,您可能想要查看控制台使用的OEM编码(可能是CP437),查找所需字符的编码,然后打印出该值。例如,CP437的字符为“☺”,你可以像这样打印出来:

#include <iostream>

int main() {
    std::cout << "\x01\n"; // ☺ has the value 0x01 in CP 437
}