流出扩展 ASCII

Streaming Out Extended ASCII

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

在Visual Studio2015年,我能做到:

cout << '\xBA';

并打印:

当我在 http://ideone.com 上尝试时,我没有打印任何东西。

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

cout << '║';

Visual Studio 发出警告:

warning C4566: character represented by universal-character-name '\u2551' cannot be represented in the current code page (1252)

然后打印:

?

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

14849425

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

这里有两个不同的概念。

第一个是语言环境之一,在Microsoft-ese中通常称为"code page"。语言环境定义了哪些视觉字符由哪个字节序列表示。在您的第一个示例中,无论您的程序以何种语言环境执行,它都会显示“║”字符,以响应字节 0xBA。

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

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

幸运的是,所有的C++关键字都使用US-ASCII,所以用什么字符集来编写C++代码并不重要。直到你开始使用非拉丁字符。这会导致编译器警告,基本上是通知您,您使用的东西可能有效,也可能无效,具体取决于结果程序运行的最终语言环境。

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

对于一个简单的字符串,编译器可以自由地做它想做的事,但它必须产生一个 const char[]。通常,编译器会尽可能保留源编码,因此程序中存储的字符串将具有输入文件的编码。在某些情况下,编译器会进行转换,例如,如果您的文件是 UTF-16(您不能在 chars 中放入 UTF-16 字符)。

当你使用 '\xBA' 时,你写了一个原始字符,你自己选择了你的编码,所以没有来自编译器的编码。

当你使用'║'时,'║'的类型不一定是char。如果字符在编译器字符集中不能表示为单个字节,则其类型将为 int。在 Visual Studio 与 Windows-1252 源文件的情况下,'║' 不适合,因此它将是 int 类型并由 [=18 这样打印=].

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

上是 UTF-32(每个字符 4 个字节)

打印到控制台只取决于变量的类型。 cout << 重载了所有常见类型,因此它的作用取决于类型。 cout << 通常会将 char 字符串按原样提供给控制台(实际上是标准输入),而 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。