我知道只有正字符ASCII值才能保证跨平台支持。
在Visual Studio 2015中,我可以这样做:
cout << '\xBA';
它打印出来:
║
当我在http://ideone.com上尝试时,我不会打印任何内容。
如果我尝试使用文字字符直接打印它:
cout << '║';
Visual Studio提供警告:
警告C4566:由通用字符名称&#39; \ u2551&#39;表示的字符无法在当前代码页(1252)中表示
然后打印:
在http://ideone.com上运行此命令时,我得到:
14849425
我已经读过wchar
可能为此提供跨平台的方法。真的吗?或者我只是在扩展的ASCII上运气不好?
答案 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。