15

您可以在 C++11 中编写 UTF-8/16/32 字符串文字,方法是分别在字符串文字前面加上u8/ u/ U。编译器必须如何解释在这些新类型的字符串文字中包含非 ASCII 字符的 UTF-8 文件?我知道该标准没有指定文件编码,仅这一事实就会使源代码中的非 ASCII 字符的解释完全未定义的行为,从而使该功能变得不那么有用。

我知道您仍然可以使用 转义单个 unicode 字符\uNNNN,但是对于通常包含多个 unicode 字符的完整俄语或法语句子来说,这不是很可读。

我从各种来源了解到的是,这u应该等同L于当前的 Windows 实现和U例如 Linux 实现。因此,考虑到这一点,我还想知道旧字符串文字修饰符所需的行为是什么......

对于代码示例猴子:

string utf8string a = u8"L'hôtel de ville doit être là-bas. Ça c'est un fait!";
string utf16string b = u"L'hôtel de ville doit être là-bas. Ça c'est un fait!";
string utf32string c = U"L'hôtel de ville doit être là-bas. Ça c'est un fait!";

在理想的世界中,所有这些字符串都产生相同的内容(如:转换后的字符),但我使用 C++ 的经验告诉我,这绝对是实现定义的,可能只有第一个会做我想要的。

4

3 回答 3

9

在 GCC 中,使用-finput-charset=charset

设置输入字符集,用于从输入文件的字符集转换为 GCC 使用的源字符集。如果 locale 没有指定,或者 GCC 无法从 locale 中获取此信息,则默认为 UTF-8。这可以被语言环境或此命令行选项覆盖。目前,如果存在冲突,命令行选项优先。charset 可以是系统的“iconv”库例程支持的任何编码。

另请查看选项-fexec-charset-fwide-exec-charset.

最后,关于字符串文字:

char     a[] = "Hello";
wchar_t  b[] = L"Hello";
char16_t c[] = u"Hello";
char32_t d[] = U"Hello";

L字符串文字 ( , u, )的大小修饰符U仅确定文字的类型

于 2011-07-22T18:45:51.013 回答
7

编译器必须如何解释在这些新类型的字符串文字中包含非 ASCII 字符的 UTF-8 文件。我知道该标准没有指定文件编码,仅这一事实就会使源代码中的非 ASCII 字符的解释完全未定义的行为,从而使该功能变得不那么有用。

来自 n3290,2.2 翻译阶段 [lex.phases]

如有必要,物理源文件字符以实现定义的方式映射到基本源字符集(为行尾指示符引入换行符)。接受的物理源文件字符集是实现定义的。[这里有一些关于三元组的内容。] 任何不在基本源字符集 (2.3) 中的源文件字符都将替换为指定该字符的通用字符名。(实现可以使用任何内部编码,只要在源文件中遇到的实际扩展字符,以及在源文件中表示为通用字符名称的相同扩展字符(即,使用 \uXXXX 表示法)是等效处理,除非此替换在原始字符串文字中恢复。)

有很多标准术语用于描述实现如何处理编码。这是我尝试对发生的事情进行更简单的分步描述:

物理源文件字符以实现定义的方式映射到基本源字符集 [...]

文件编码的问题是手动的;标准只关心基本的源字符集,并为实现留下空间。

任何不在基本源字符集 (2.3) 中的源文件字符都将替换为指定该字符的通用字符名。

基本源集是一个简单的允许字符列表。它不是 ASCII(见进一步)。不在此列表中的任何内容都被“转换”(至少在概念上)为一种\uXXXX形式。

所以无论使用何种文字或文件编码,源代码在概念上都转化为基本字符集 + 一堆\uXXXX. 我从概念上说是因为实现实际所做的通常更简单,例如因为它们可以直接处理 Unicode。重要的部分是标准所称的扩展字符(即不是来自基本源集)在使用中应该与它的等效\uXXXX形式没有区别。请注意,C++03 在例如 EBCDIC 平台上可用,因此您在 ASCII 方面的推理从一开始就有缺陷。

最后,我描述的过程也发生在(非原始)字符串文字上。这意味着您的代码等效于您编写的代码:

string utf8string a = u8"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
string utf16string b = u"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
string utf32string c = U"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
于 2011-07-22T20:24:39.583 回答
0

原则上,编码问题仅在您通过使人类可见来输出字符串时才重要,这不是编程语言如何定义的问题,因为它的定义仅涉及编码计算。因此,当您决定您在编辑器中看到的内容是否与您在输出中看到的相同(任何类型的图像,无论是在屏幕上还是在 pdf 中)时,您应该问自己哪个约定假设您的用户交互库和操作系统的编码方式。(例如,这里是Qt5的这种信息:对于 Qt5,如果您的 QStrings 的老式字符串文字的内容在源文件中编码为 utf8,除非您打开另一个设置在应用程序的执行过程中)。

作为结论,我认为 Kerrek SB 是对的,而 Damon 是错的:确实,在代码中指定字面量的方法应该指定它的类型,而不是源文件中用于填充其内容的编码,因为文字的类型是对它进行的计算。类似的东西u"string"只是一个“unicode codeunits”数组(即类型的值char16_t),无论操作系统或任何其他服务软件后来对他们做什么,无论他们的工作是为您或其他用户寻找的。您只是遇到了为自己添加另一个约定的问题,它在计算中的数字的“含义”(即它们呈现 Unicode 的代码)和它们在您在文本编辑器中工作时在屏幕上的表示之间建立了对应关系. 作为程序员,您如何以及是否使用该“含义”是另一个问题,您如何强制执行其他对应关系自然是实现定义的,因为它与编码计算无关,仅与工具使用的舒适性有关.

于 2015-10-10T15:02:43.800 回答