在 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-16
或utf-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_t
和 char32_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 字符串?