这个UTF-8实现是实现定义的还是定义良好的?

时间:2016-01-01 22:34:17

标签: c++ string unicode utf-8

我只是浏览了一下寻找UTF-8代码点的一些实现(不,不是抄袭)并偶然发现this

typedef unsigned char char8_t;
typedef std::basic_string<unsigned char> u8string;

这段代码是否忽略了CHAR_BIT只需要至少8,但可能更大的事实?或者这在这种情况下无关紧要且代码没问题?如果是这样,那为什么呢?

另外,某人(可能是SO成员@NicolBolas?)写道:

const char *str = u8"This is a UTF-8 string.";
     

这几乎就是如何在C ++中将字符串文字用于UTF-8。

我认为UTF-8中的代码单元总是正好是8位! 从Unicode标准8.0.0,第2.5章:

  

在Unicode字符编码模型中,精确定义编码   表单指定Unicode字符的每个整数(代码点)的方式   表示为一个或多个代码单元的序列。 Unicode   Standard为Unicode提供了三种不同的编码形式   字符,使用 8位,16位和32位单位。这些是   分别命名为 UTF-8 ,UTF-16和UTF-32。

(删除换行符,删除换行符上的连字符,添加强调。)

那么为什么他声称const char*代替const uint8_t*(或建议的假设const char8_t*)?

5 个答案:

答案 0 :(得分:3)

uint8_t仅存在于内存可以作为完全 8位访问的系统上。 UTF-8没有任何此类要求。它使用适合8位的值,但不对这些值的实际存储方式施加任何要求。每个8位值可以存储为16位或32位,或者对于正在运行的系统有意义的任何值;唯一的要求是价值必须正确。

答案 1 :(得分:1)

  

[lex.string] / 8 普通字符串文字和UTF-8字符串文字也称为窄字符串文字。窄字符串文字的类型为“n const char”数组,其中n是下面定义的字符串大小,并且具有静态存储持续时间(3.7)。

所以,无论如何,UTF-8字符串文字都是char s的序列。

关于uint8_t

  

<强> 7.20.1.1

     

2 typedef名称uintN_t指定宽度为N且无填充位的无符号整数类型。因此,uint24_t表示这样的无符号整数类型,其宽度恰好为24位。

     

3这些类型是可选的。但是,如果实现提供宽度为8,16,32或64位的整数类型,没有填充位,并且(对于带有二进制补码表示的有符号类型),它应定义相应的typedef名称。

char大于8位的假设系统中,不会定义uint8_t

答案 2 :(得分:1)

  

那么为什么他声称const char*代替const uint8_t*(或建议的假设const char8_t*)?

因为那是标准所说的。 u8文字字符串将解析为const char[N]类型的数组。这就是如何定义C ++中的UTF-8文字是如何工作的。

如果系统上的char超过8位......那就这样吧。字符串中的每个char仍将保留0到255之间的值,这是有效UTF-8代码单元的范围。即使char可以在此类系统上保留较大的值。

如果char不能容纳8位......那么实现无效。根据标准的最近措辞,char需要保留足够的位来存储每个有效的UTF-8代码单元。从技术上讲,255不是有效的UTF-8代码单元。

事实就是这样:已经有巨大的数量的代码通过char*接受UTF-8。他们不会重写POSIX,文件系统API,以及采用不同类型的其他任何东西。

话虽如此,通过const char*操纵一系列UTF-8代码单元是......可疑的。这是因为他们可以签名。但是,最近的标准措辞要求unsigned charchar之间的转换在有效的UTF-8代码单元范围内工作。也就是说,您可以将const char*投射到const unsigned char*,对其进行操控,然后将其转回,并确保您能够正常工作。

  

那个超级复杂的标准&#34;最近的标准&#34;是什么意思?

关键是允许UTF-8字符串实际工作。因为标准委员会在其无限智慧&#34;中决定不包含特殊的char8_t UTF-8代码单元类型,所以他们必须添加措辞以使char服务于角色。这要求转换为unsigned charchar的转换不能破坏UTF-8代码单元。

甚至有一个discussion topic on the C++ standard discussion forumswording was discussed (search for 1759)。 C ++ 14的措辞说:

  

对于0到255(包括0和255)范围内i类型的每个值unsigned char,存在j类型的值char,以便进行积分转换(4.7)从icharj,从junsigned char的整数转换结果为i

这尤其意味着,如果签名的表示符合上述要求,则char只能默认签名。签名char的补码是不够的,因为负零具有特殊表示(0x80),当转换为无符号时变为常规0。

他们是否刚刚定义了一个特定的char8_t,它必须是无符号的且至少有8位?大概。但它已经完成而且它没有改变。

答案 3 :(得分:0)

UTF-8中的

代码单元总是正好是8位unsigned char被指定为至少有8位,因此UTF-8中的所有代码单元都符合unsigned char类型。

u8"This is a UTF-8 encoded string constant"的基本原理不是它以8位字节存储,而是以UTF-8编码,而源文件可能有不同的编码。 u8string typedef与此一致,但如果字节超过8位,则会引起混淆。

使用unsigned char是消除有关char类型签名的不确定性的好方法。

答案 4 :(得分:0)

char8_t在圣地亚哥会议上被投票选为C ++ 20,因此该代码将无法编译。

但是,您将能够使用std::u8string,但请记住,它仅适用于代码单元,不适用于代码点或字形簇,因此安全的方法是将其视为不透明的斑点并使用3rd party库进行变异它。至少现在。