流式传输扩展ASCII

时间:2016-03-02 12:56:16

标签: c++ char streaming extended-ascii wchar

我知道只有正字符ASCII值才能保证跨平台支持。

在Visual Studio 2015中,我可以这样做:

cout << '\xBA';

它打印出来:

  

当我在http://ideone.com上尝试时,我不会打印任何内容。

如果我尝试使用文字字符直接打印它:

cout << '║';

Visual Studio提供警告:

  

警告C4566:由通用字符名称&#39; \ u2551&#39;表示的字符无法在当前代码页(1252)中表示

然后打印:

  

http://ideone.com上运行此命令时,我得到:

  

14849425

我已经读过wchar可能为此提供跨平台的方法。真的吗?或者我只是在扩展的ASCII上运气不好?

2 个答案:

答案 0 :(得分:1)

这里有两个独立的概念。

第一个是区域设置之一,在Microsoft-ese中通常称为“代码页”。区域设置定义哪个可视字符由哪个字节序列表示。在您的第一个示例中,无论您的程序执行的语言环境如何,它都会显示“║”字符,以响应字节0xBA。

其他区域设置或代码页将为相同的字节显示不同的字符。许多语言环境都是多字节语言环境,可能需要几个字节才能显示单个字符。例如,在UTF-8语言环境中,相同的字符║需要三个字节才能显示:0xE2 0x95 0x91。

这里的第二个概念是源代码字符集之一,它来自编辑源代码的语言环境,在编译之前。当您在源代码中输入║字符时,如果您的编辑器使用UTF-8语言环境,它可能会表示为0xBA字符,或者可能是0xE2 0x95 0x91序列。编译器在读取源代码时,只看到实际的字节序列。一切都减少到了字节。

幸运的是,所有C ++关键字都使用US-ASCII,因此使用哪个字符集来编写C ++代码并不重要。直到你开始使用非拉丁字符。这导致编译器警告,通知您,基本上,您正在使用可能或可能不起作用的内容,具体取决于生成的程序运行的最终区域设置。

答案 1 :(得分:1)

首先,您的输入源文件有自己的编码。您的编译器需要能够读取此编码(可能借助于flags / settings)。

使用简单的字符串,编译器可以自由地执行它想要的操作,但它必须产生const char[]。通常,编译器会在时保持源编码,因此存储在程序中的字符串将具有输入文件的编码。有些情况下编译器会进行转换,例如,如果您的文件是UTF-16(您不能在char s中使用UTF-16字符)。

当您使用'\ xBA'时,您编写了一个原始字符,并且您自己选择了编码,因此编译器没有编码。

使用'║'时,'║'的类型不一定是char。如果字符不能表示为编译器字符集中的单个字节,则其类型将为int。对于带有Windows-1252源文件的Visual Studio,'║'不适合,因此它将是int类型,并由cout <<打印。

您可以在字符串文字上强制使用前缀进行编码。 u8""会强制使用UTF-8,u"" UTF-16和U"" UTF-32。请注意,L""前缀会为您提供广泛的字符wchar_t字符串,但它仍然依赖于实现。 Windows上的宽字符是UCS-2(每个字符2个字节),但是linux上的UTF-32(每个字符4个字节)。

仅打印到控制台取决于变量的类型。 cout <<重载了所有常见类型,因此它的作用取决于类型。 cout <<通常会将char个字符串提供给控制台(实际上是stdin),而wcout <<通常会按原样提供wchar_t个字符串。其他组合可能会有转化或解释(例如提供int)。 UTF-8字符串是char字符串,因此cout <<应该始终正确地提供它们。

接下来,有控制台本身。控制台是一个完全独立的软件。你喂它一些字节,它显示它们。 对您的计划不关心。它使用自己的编码,并尝试使用此编码打印您提供的字节。

Windows上的默认控制台编码是代码页850(不确定是否总是如此)。在您的情况下,您的文件是CP 1252,而您的控制台是CP 850,这就是您无法直接打印'║'(CP 1252不包含'║')的原因,但您可以使用原始文件字符。您可以使用SetConsoleCP()更改Windows上的控制台编码。

在linux上,默认编码是UTF-8,这更方便,因为它支持整个Unicode范围。 Ideone使用linux,因此它将使用UTF-8。请注意,增加了HTTP和HTML层,但它们也使用UTF-8。