C++中的UTF-8兼容性

Qma*_*man 11 c++ unicode wchar-t utf-8 wstring

我正在编写一个程序,需要能够使用所有语言的文本.我的理解是UTF-8将完成这项工作,但我遇到了一些问题.

我是否可以说UTF-8可以存储char在C++中?如果是这样,为什么我在使用程序时会收到以下警告char,string并且stringstream:warning C4566: character represented by universal-character-name '\uFFFD' cannot be represented in the current code page (1252).(我使用时没有出现错误wchar_t,wstring并且wstringstream.)

另外,我知道UTF是可变长度的.当我使用atsubstr字符串方法时,我会得到错误的答案?

R. *_*des 15

要使用UTF-8字符串文字,您需要为它们添加前缀u8,否则您将获得实现的字符集(在您的情况下,它似乎是Windows-1252):u8"\uFFFD"是以字节为单位的UTF-8表示的字节序列替换字符(U + FFFD).它有类型char const[4].

由于UTF-8具有可变长度,因此所有类型的索引都将以代码单元而不是代码点进行索引.由于UTF-8序列具有可变长度特性,因此无法对代码点进行随机访问.如果要随机访问,则需要使用固定长度编码,如UTF-32.为此,您可以U在字符串上使用前缀.

  • 到目前为止我使用前缀`L`.我尝试用'u8`替换它但我收到错误`错误C2065:'u8':未声明的标识符`. (2认同)
  • UTF-32是代码点的固定长度编码,但Unicode是字符的基本可变长度表示,因为多个代码点可用于表示字符.无论您使用UTF-32还是其他任何内容,都无法随机访问字符.幸运的是,随机访问很少(如果有的话)需要. (2认同)

bam*_*s53 10

是的,UTF-8编码可以与char,string和stringstream一起使用.char将包含单个UTF-8代码单元,其中可能需要多达四个代码单元来表示单个Unicode代码点.

但是,使用UTF-8特别是微软的编译器存在一些问题.C++实现对许多事物使用"执行字符集",例如编码字符和字符串文字.VC++总是使用系统区域设置编码作为执行字符集,而Windows不支持UTF-8作为系统区域设置编码,因此UTF-8永远不能通过执行字符集.

这意味着VC++从不故意产生UTF-8字符和字符串文字.相反,编译器必须被欺骗.

编译器将从已知的源代码编码转换为执行编码.这意味着如果编译器对源代码和执行编码使用区域设置编码,则不会进行任何转换.如果您可以将UTF-8数据放入源代码中,但让编译器认为源使用区域设置编码,则字符和字符串文字将使用UTF-8编码.VC++使用所谓的"BOM"来检测源编码,如果没有检测到BOM,则使用区域设置编码.因此,您可以通过将所有源文件保存为"UTF-8 without signature"来获取UTF-8编码的字符串文字.

这种方法有一些警告.首先,您不能使用具有窄字符和字符串文字的UCN.通用字符名称必须转换为执行字符集,而不是UTF-8.您必须按字面意思编写字符,使其在源代码中显示为UTF-8,或者您可以使用十六进制转义符来手动写出UTF-8编码.其次,为了生成宽字符和字符串文字,编译器执行从源编码到宽执行字符集(在VC++中始终为UTF-16)的类似转换.由于我们对编译器撒谎,它将错误地执行此转换为UTF-16.因此,在宽字符和字符串文字中,您不能逐字地使用非ascii字符,而是必须使用UCN或十六进制转义符.


UTF-8是可变长度的(与UTF-16一样).所使用的指数at()substr()代码单元,而不是字符或代码点指数.因此,如果您想要一个特定的代码单元,那么您可以只索引到字符串或数组或正常情况下.如果您需要特定的代码点,那么您需要一个可以理解将UTF-8代码单元组合成代码点的库(例如Boost Unicode迭代器库),或者您需要将UTF-8数据转换为UTF-32.如果您需要实际的用户感知字符,那么您需要一个能够理解代码点如何组成字符的库.我想ICU具有这样的功能,或者您可以从Unicode标准实现Default Grapheme Cluster Boundary Specification.


以上对UTF-8的考虑仅对您在源代码中编写Unicode数据的方式非常重要.它对程序的输入和输出几乎没有影响.

如果您的要求允许您选择如何进行输入和输出,那么我仍然建议使用UTF-8进行输入.根据您需要对输入执行的操作,您可以将其转换为易于处理的其他编码,也可以编写处理例程以直接在UTF-8上工作.

如果你想通过Windows控制台输出任何东西,那么你需要一个定义良好的输出模块,它可以有不同的实现,因为到Windows控制台的国际化输出需要在Windows或控制台上输出到文件的不同实现和其他平台上的文件输出.(在其他平台上,控制台只是另一个文件,但Windows控制台需要特殊处理.)

  • 请注意,您可以使用 MSVC 上的“/utf-8”标志覆盖源和执行字符集:https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source -and-executable-character-sets-to-utf-8 (2认同)