在 C++ 源代码中使用 Unicode

Posted

技术标签:

【中文标题】在 C++ 源代码中使用 Unicode【英文标题】:Using Unicode in C++ source code 【发布时间】:2010-09-24 19:20:27 【问题描述】:

C++ 源代码的标准编码是什么? C++ 标准是否对此有所说明?我可以用 Unicode 编写 C++ 源代码吗?

比如可以在cmets中使用汉字等非ASCII字符吗?如果是这样,是否允许完整的 Unicode 或只是 Unicode 的子集? (例如,那个 16 位的首页或其他名称。)

此外,我可以对字符串使用 Unicode 吗?例如:

Wstring str=L"Strange chars: â Țđ ě €€";

【问题讨论】:

RE: "不管它叫什么": From Wikipedia: 第一个平面,plane 0基本多语言平面(BMP ) 包含几乎所有现代语言的字符,以及大量的符号。 BMP 的主要目标是支持统一先前的字符集以及用于书写的字符。 BMP 中分配的大多数代码点用于编码中文日文韩文(CJK)字符。 我有一个有趣的变种。我的日志中有一个 UTF-8 字符 µ 显示为 µ。我怀疑 GNU g++ 假定了 iso-8859-1 源代码并过度编码了二进制文件中的单字符两字节序列。实际上它理解源是基于语言环境的 UTF-8。日志包含正确的两字节序列。事实上,日志的另一部分包含杂散字节,这些字节在文件中引入了不符合 UTF-8 的字节序列。因此,编辑器 emacs 确定该文件实际上是 ISO-8859-1,并将两字节字符显示为两个单独的字符。修复那些杂散字节解决了问题。 【参考方案1】:

C++ 中的编码相当复杂。这是我的理解。

每个实现都必须支持来自基本源字符集的字符。其中包括第 2.2/1 节(C++11 中的第 2.3/1 节)中列出的常见字符。这些字符都应该适合一个char。此外,实现必须支持一种使用称为universal-character-names 的方式命名其他字符的方式,并且看起来像\uffff\Uffffffff,并且可以用来引用Unicode 字符。它们中的一个子集可用于标识符(在附件 E 中列出)。

这一切都很好,但是从文件中的字符到源字符(在编译时使用)的映射是实现定义的。这构成了所使用的编码。以下是它的字面意思(C++98 版本):

物理源文件字符是 映射,在实现定义的 方式,到基本的源字符 设置(引入换行符 对于行尾指标)如果 必要的。三字母序列 (2.3) 被相应的替换 单字符内部 申述。任何源文件 字符不在基本来源中 字符集(2.2)被替换为 通用字符名称 点燃那个角色。 (一个 实现可以使用任何内部 编码,只要一个实际的 中遇到的扩展字符 源文件,和相同的扩展 源文件中表示的字符 作为通用字符名称(即 使用 \uXXXX 符号),是 等价处理。)

对于 gcc,您可以使用选项 -finput-charset=charset 更改它。此外,您可以更改用于在运行时表示值的执行字符。正确的选项是-fexec-charset=charset 用于char(默认为utf-8)和-fwide-exec-charset=charset(默认为utf-16utf-32,具体取决于wchar_t 的大小)。

【讨论】:

【参考方案2】:

据我所知,C++ 标准没有提及源代码文件编码。

通常的编码是(或曾经是)7 位 ASCII——一些编译器(例如 Borland 的)会拒绝使用高位的 ASCII 字符。没有技术原因不能使用 Unicode 字符,如果你的编译器和编辑器接受它们——大多数现代的基于 Linux 的工具,以及许多更好的基于 Windows 的编辑器,都可以毫无问题地处理 UTF-8 编码,尽管我'不确定微软的编译器会不会。

编辑:看起来微软的编译器会接受 Unicode 编码的文件,但有时也会在 8 位 ASCII 上产生错误:

warning C4819: The file contains a character that cannot be represented
in the current code page (932). Save the file in Unicode format to prevent
data loss.

【讨论】:

确实如此。我不认为它明确禁止或允许 unicode,但这是允许的最小字符集:csci.csusb.edu/dick/c++std/cd2/lex.html#lex.charset 自 C++Builder2007 起,Borland/Codegear 编译器支持 unicode 源文件:即 Unicode 字符串文字,unicode cmets。 IDe 与他们有点挣扎,但编译器很高兴! 我提到的 Borland 东西大约是 20 年前的事了(我最后一次尝试在源代码文件中放入高位 ASCII 字符)。 :-) 我已经有十年没用过 Borland 编译器了。 Microsoft 编译器仅支持宽字符 (L"...") 的 Unicode。【参考方案3】:

除了 litb 的帖子,MSVC++ 也支持 Unicode。我知道它从 BOM 中获取 Unicode 编码。它绝对支持int (*♫)();const std::set<int> ∅; 之类的代码 如果你真的很喜欢代码混淆:

typedef void ‼; // Also known as \u203C
class ooɟ 
    operator ‼() 
;

【讨论】:

这对于编写例如可以将源代码与源材料对齐的数学软件很有用。您可以在接受 UTF-8 源代码的 Java 中执行此操作。但是,对于 C++(和 C),在如何将非 ASCII 标记转换为符号名称方面可能存在问题,这必须与操作系统的其余部分兼容——而不仅仅是编译器的一个特性。对于 C++,这可以包含在名称修饰中。【参考方案4】:

这里有两个问题。首先是 C++ 代码(和 cmets)中允许使用的字符,例如变量名。第二个是字符串和字符串字面量中允许使用哪些字符。

如上所述,C++ 编译器必须为代码和 cmets 中允许的字符支持非常受限的基于 ASCII 的字符集。在实践中,这个字符集不能很好地与一些欧洲字符集配合使用(尤其是一些没有几个字符的欧洲键盘——比如方括号——可用),所以二合字母和三合字母的概念是介绍了。许多编译器目前接受的字符集不止这个字符集,但没有任何保证。

对于字符串和字符串字面量,C++有宽字符和宽字符串的概念。但是,该字符集的编码是未定义的。实际上,它几乎总是 Unicode,但我认为这里没有任何保证。宽字符串字面量看起来像 L“字符串字面量”,它们可以分配给 std::wstring 的。


C++11 添加了对 Unicode 字符串和字符串文字的显式支持,编码为 UTF-8、UTF-16 大端、UTF-16 小端、UTF-32 大端和 UTF-32 小端。

【讨论】:

【参考方案5】:

对于字符串中的编码,我认为您应该使用 \u 表示法,例如:

std::wstring str = L"\u20AC"; // Euro character

【讨论】:

【参考方案6】:

同样值得注意的是,C++ 中的宽字符并不是真正的 Unicode 字符串。它们只是较大字符的字符串,通常为 16 位,但有时为 32 位。这是实现定义的,但是,IIRC 你可以有一个 8 位的 wchar_t 你对它们中的编码没有真正的保证,所以如果你试图做一些像文本处理这样的事情,你可能需要一个 typedef最适合您的 Unicode 实体的整数类型。

C++1x 以 UTF-8 编码字符串文字 (u8"text") 和 UTF-16 和 UTF-32 数据类型(char16_tchar32_t IIRC)以及对应的字符串常量(u"text"U"text")。但是,没有\uxxxx\Uxxxxxxxx 常量指定的字符的编码仍然是实现定义的(并且不支持文字之外的复杂字符串类型的编码)

【讨论】:

小写字面 u 不是只代表字符吗?【参考方案7】:

在这种情况下,如果您收到 MSVC++ 警告 C4819,只需将源文件编码更改为“UTF-8 with Bom”即可。

GCC 4.1 不支持这个,但是 GCC 4.4 支持,并且最新的 Qt 版本使用的是 GCC 4.4,所以使用“UTF-8 with Bom”作为源文件编码。

【讨论】:

【参考方案8】:

AFAIK 它不是标准化的,因为您可以将任何类型的字符放在宽字符串中。 您只需检查您的编译器是否设置为 Unicode 源代码以使其正常工作。

【讨论】:

以上是关于在 C++ 源代码中使用 Unicode的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中将字符串从十进制代码转换为西里尔文/unicode16?

在 C++ 中打开 Unicode 文本文件并显示其内容

如何在 C++ 中将字符的十进制代码转换为 Unicode 字符串?

在 C++ 中获取 unicode 字符的 CodePoint

C++ 中的 Unicode 字符串处理

Visual C++:将传统 C 和 C++ 字符串代码迁移到 Unicode 世界