根据ISO / IEC在不同的字符集编码(如UTF-16)中混淆sizeof(char)

假设一个程序在UTF-16编码字符集的系统上运行。 所以根据The C ++ Programming Language – 4th ,第150页:

char可以保存机器字符集的一个字符。

→我认为charvariables的大小是2个字节。

但根据ISO / IEC 14882:2014

sizeof(char)sizeof(signed char)sizeof(unsigned char)是1“。

C ++编程语言 – 第4页,第149页:

“[…],所以根据定义,字符的大小是1”

→大小固定为1。

问题:上述这些语句之间是否存在冲突,或者是sizeof(char) = 1只是一个默认(定义)值,并且实现定义取决于每个系统?

C ++标准(和C,就此而言)有效地将byte定义为chartypes的大小, 而不是 8位数量1 。 按照C++11 1.7/1 (我的粗体):

C ++内存模型中的基本存储单元是字节。 一个字节至less足以包含基本执行字符集的任何成员和Unicode UTF-8编码forms的八位代码单元,并且由一个连续的位序列组成, 其数目是实现定义的。

因此,expression式sizeof(char) 总是 1,不pipe怎样。

如果你想看看你的底线charvariables(可能是unsignedvariables是最好的)实际上可以保存一个16位的值,你想看的项目是来自<climits> CHAR_BIT 。 这保存了charvariables中的位数。


1许多标准,特别是与通信协议相关的标准,使用octet更精确的octet

是的,在string的C ++混合中存在一些严重的冲突和问题,而且这个问题也混合了一些东西。 所以,一个简单的直接答案就好像回答“是”,“否”或“不知道”这个问题“你停止殴打你的妻子了吗?”。 唯一直接的答案是佛教“亩” ,不问这个问题。

所以,让我们先看看事实。


关于字符types的事实。

每个char的位数是由<limits.h>头文件中实现定义的CHAR_BIT给出的。 这个数字保证是8或更大。 在C ++ 03及更早版本中,保证来自C89标准中的该符号的规范,C ++标准(在非规范性章节中,但仍然)将其标注为“合并”。 对于C ++ 11及更高版本,C ++标准明确地给出了≥8的保证。 在大多数平台上, CHAR_BIT是8,但在一些可能仍然存在的德州仪器数字信号处理器中,它是16,而其他值已被使用。

无论CHAR_BIT的值是CHAR_BITsizeof(char)的定义都是1,即没有实现的定义:

C ++ 11§5.3.3/ 1 (在[expr.sizeof]中):

sizeof(char)sizeof(signed char)sizeof(unsigned char)是1。

也就是说, char和它的变体是内存寻址的基本单位 ,这是字节的主要含义,无论是在普通语言还是在C ++中:

C ++ 11§1.7/ 1 (in [intro.memory]):

C ++内存模型中的基本存储单元是字节

这意味着在前面提到的TI DSP上,没有C ++获取单个八位字节 (8位部分)的指针的方法。 而这又意味着需要处理字节序的代码或者以其他方式需要将char值视为八位字节序列(特别是用于networking通信)的代码需要使用在CHAR_BIT的系统上无意义的char值是8.这也意味着普通的C ++窄string文字,如果坚持标准的话,而且如果平台的标准软件使用8位字符编码的话,会浪费内存。

Pascal语言直接解决了这个浪费问题,它区分了压缩string (每个字节多个八位字节)和未压缩string (每个字节一个八位字节),其中前者用于被动文本存储,后者是用于高效处理。

这说明了单个C ++typeschar中三个方面的基本结合:

  • 内存寻址单元,又名字节,

  • 最小的基本types(这将是一个octettypes),和

  • 字符编码值单位。

是的,这是一个冲突。


关于UTF-16编码的事实。

Unicode是一组21位的代码点 ,其中大部分是自己构成的字符,但其中一些与其他字符组合形成字符。 例如,可以通过将“e”和“'”作为重音的代码点组合来形成具有类似“é”的口音的字符。 而且由于这是一个通用机制,所以它意味着一个Unicode字符可以是任意数量的代码点,尽pipe通常只有1个。

当Unicode扩展为每个代码点21位时,UTF-16编码最初是一种基于原始Unicode的每个代码点16位代码的兼容性scheme。 基本的scheme是原始Unicode定义范围内的代码点表示为它们自己,而每个新的Unicode代码点表示为16位值的替代对 。 代理对值使用小范围的原始Unicode。

当时,基于每码点16位软件的例子包括32位Windows和Java语言。

在具有8位字节UTF-16的系统上是宽文本编码的例子,即编码单元比基本可寻址单元宽。 字节为导向的文本编码被称为窄文本 。 在这样的系统上,C ++ char适合后者,但不适用于前者。

在C ++ 03中,适用于宽文本编码单元的唯一内置types是wchar_t

但是,C ++标准有效地要求wchar_t适合于代码点 ,对于现代21位每代码点Unicode来说,它意味着它需要是32位。 因此,没有C ++ 03专用types适合UTF-16编码值的要求,每个值16位。 由于历史原因,基于UTF-16作为宽文本编码的最普遍的系统,即Microsoft Windows,将wchar_t定义为16位,这在Unicode的扩展之后已经与标准公然矛盾,但是这样的标准是不切实际的关于这个问题。 有些平台将wchar_t定义为32位。

C ++ 11引入了新的typeschar16_tchar32_t ,前者被devise为适合于UTF-16编码值。


关于这个问题。

关于这个问题的陈述假设

“一个使用UTF-16编码字符集的系统

这可能意味着两件事之一:

  • 一个以UTF-16作为标准窄编码的系统,或者
  • 作为标准宽编码的UTF-16系统。

用UTF-16作为标准的窄编码CHAR_BIT ,和(按定义) sizeof(char) = 1。我不知道任何系统,即它似乎是假设的。 然而,这似乎是目前其他答案默认的含义。

用UTF-16作为标准的宽编码,就像在Windows中一样,情况比较复杂,因为C ++标准不能胜任。 但是,以Windows为例,一个实际的可能性是sizeof(wchar_t) = 2。应该注意的是,这个标准与这个问题的现有实践和实际考虑是冲突的,当理想是标准而不是标准化现有的做法,哪里有这样的。

现在我们终于可以处理这个问题了,

上面的这些语句之间是否存在冲突,或者sizeof(char) = 1只是一个默认(定义)值,并且将由实现定义,取决于每个系统?

这是一个错误的二分法。 两种可能性不是相反的。 我们有

  • char作为字符编码单元和内存寻址单元(字节)之间确实存在冲突。 如上所述,Pascal语言有关键字packed处理冲突的一个方面,即存储与处理要求。 wchar_t的forms化要求与使用UTF-16编码的最广泛使用的系统(即Windows)中的UTF-16编码之间还有进一步的冲突。

  • sizeof(char) = 1的定义:它不是系统相关的。

  • CHAR_BIT是实现定义的,保证≥8。

不,没有冲突。 这两个语句引用了不同的字节定义。

UTF-16意味着该字节八位 字节相同 – 一组8位。

在C ++语言中, 字节char相同。 对于C ++字节可以包含多less位没有限制。 C ++中的位数 – 字节由CHAR_BITmacros常量定义。

如果您的C ++实现决定使用16位来表示每个字符,那么CHAR_BIT将是16,每个C ++字节将占用两个UTF-16字节。 sizeof(char)仍然是1,所有对象的大小将以16位字节来衡量。

char被定义为1个字节。 一个字节是最小的可寻址单元。 这是普通系统上的8位,但是在某些系统上,它是16位或32位,或者其他的(但是对于C ++来说,必须至less是8位)。

这有些令人困惑,因为在stream行的术语中, 字节用于技术上称为八位字节 (8位)的字节

所以,你的第二和第三个引号是正确的。 第一句话严格来说是不正确的。

正如C ++标准中的[intro.memory] ​​/ 1所定义的, char只需要能够保存大约100个字符的基本执行字符集 (所有这些字符集都出现在ASCII的0-127范围内),而组成UTF-8编码的八位字节。 也许这就是作者所说的机器字符集。


在硬件是八位字节可寻址但字符集是Unicode的系统上, char可能会保持8位。 但是, char16_tchar32_t (在C ++ 11中添加)的types被devise用于代码,而不是用于具有16位或32位字符集的系统的字符。

因此,如果系统使用char16_t那么您将使用std::basic_string<char16_t>而不是std::string ,依此类推。

究竟如何处理UTF-16将取决于系统select的实施细节。 Unicode是21位字符集,UTF-16是它的多字节编码; 所以系统可以使用类似Windows的路由,并使用带有UTF-16编码的std::basic_string<char16_t>string; 或者可以使用原始Unicode代码点作为字符的std::basic_string<char32_t>

阿尔夫的文章详细解释了一些可能出现的问题。

不用引用标准就很容易给出答案,因为:

字节的定义不是8位 。 字节是任何大小,但最小的可寻址单元的内存。 最常见的是8位,但没有理由没有16位的字节。

C ++标准给出了更多的限制,因为它必须至less有8位。

所以不pipesizeof(char)总是1,没有问题。 有时候它会像8位,有时候是16位等等。