首页 文章

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

提问于
浏览
37

假设程序在具有UTF-16编码字符集的系统上运行 . 所以根据C编程语言 - 第4页,第150页:

char可以保存机器字符集的字符 .

→我认为char变量的大小是2字节 .

但根据ISO / IEC 14882:2014:

sizeof(char),sizeof(signed char)和sizeof(unsigned char)是1“ .

或C语言程序设计 - 第4页,第149页:

“[...],因此根据定义,char的大小为1”

→固定尺寸为1 .

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

5 回答

  • 28

    C标准(和C,就此而言)有效地将 byte 定义为 char 类型的大小,而不是8位数量1 . 根据 C++11 1.7/1 (我的大胆):

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

    因此表达式 sizeof(char) 总是1,无论如何 .

    如果你想看看你是否基线 char 变量(可能 unsigned 变体最好)实际上可以保持一个16位值,你要查看的项目是 <climits> 来自 <climits> . 这保存 char 变量中的位数 .


    1许多标准,尤其是与通信协议相关的标准,对于8位值使用更精确的术语 octet .

  • 35

    是的,对于 char 的C合并存在许多严重的冲突和问题,但这个问题也混淆了一些问题 . 因此,一个简单的直接回答就是回答“是的”,“不”或“不知道”问题“你有没有停止殴打你的妻子?” . 唯一的直接答案是the buddhist “mu”,没有问题 .

    因此,让我们先看看事实 .


    关于char类型的事实 .

    每个 char 的位数由 <limits.h> 标头中定义的 CHAR_BIT 实现给出 . 此数字保证为8或更大 . 对于C 03及更早版本,保证来自C89标准中该符号的规范,C标准指出(在非规范部分,但仍然)为“合并” . 对于C 11及更高版本,C标准本身明确地给出了≥8保证 . 在大多数平台上 CHAR_BIT 是8,但有些可能仍然存在Texas Instruments digital signal processors它是16,并且已经使用了其他值 .

    无论 CHAR_BIT 的值如何 sizeof(char) 定义为1,即它不是实现定义的:
    C++11 §5.3.3/1 (在[expr.sizeof]中):

    “sizeof(char),sizeof(signed char)和sizeof(unsigned char)为1 .

    也就是说, char 及其变体是记忆寻址的基本单位,这是 byte 的主要含义,无论是在普通语音中还是在C语言中:
    C++11 §1.7/1 (在[intro.memory]中):

    “C存储器模型中的基本存储单元是字节 .

    这意味着在前面提到的TI DSP上,没有C方式获得指向单个 octets (8位部分)的指针 . 而这反过来意味着需要处理字节序的代码,或者其他方式需要将 char 值视为八位字节序列,特别是对于网络通信,需要使用 char 值来处理 char 它也意味着普通的C窄字符串文字,如果它们符合标准,并且如果平台的标准软件使用8位字符编码,则会浪费内存 .

    废物方面是(或是)用Pascal语言直接处理,它区分 packed strings (每个字节多个八位字节)和 unpacked strings (每个字节一个八位字节),前者用于被动文本存储,后者用于高效的处理 .

    这说明了单个C类型 char 中三个方面的基本混淆:

    • 内存寻址单位,即.k.a . 字节,

    • 最小的基本类型(对于 octet 类型会很好),和

    • 字符编码值单位 .

    是的,这是一场冲突 .


    关于UTF-16编码的事实 .

    Unicode很大一组21位 code points ,其中大部分都是自己构成的字符,但其中一些与其他字符组合形成字符 . 例如 . 可以通过组合“e”和“'” - 重音的代码点来形成具有类似“é”的重音的字符 . 由于这是一种通用机制,因此它意味着Unicode字符可以是任意数量的代码点,尽管它通常只有1 .

    UTF-16编码最初是基于每个代码点的原始Unicode 16位代码的兼容性方案,当Unicode扩展到每个代码点21位时 . 基本方案是原始Unicode的定义范围中的代码点表示为自身,而每个新的Unicode代码点表示为16位值的 surrogate pair . 一小部分原始Unicode用于代理对值 .

    当时,基于每个代码点16位的软件示例包括32位Windows和Java语言 .

    在具有8位字节的系统上,UTF-16是 wide text 编码的示例,即具有比基本可寻址单元宽的编码单元 . 面向字节的文本编码则称为 narrow text . 在这样的系统上,C char 适合后者,但不适合前者 .

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

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

    C 11引入了新类型 char16_tchar32_t ,其中前者(设计为)适用于UTF-16编码值 .


    关于这个问题 .

    关于问题的陈述假设

    “具有UTF-16编码字符集的系统

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

    • 使用UTF-16作为标准窄编码的系统,或

    • 使用UTF-16作为标准宽编码的系统 .

    使用UTF-16作为标准窄编码 CHAR_BIT ≥16,并且(根据定义) sizeof(char) = 1.我不知道任何系统,即它似乎是假设的 . 然而,它似乎是当前其他答案中默认的含义 .

    使用UTF-16作为标准的宽编码,就像在Windows中一样,情况更复杂,因为C标准不能胜任任务 . 但是,以Windows为例,一个实际的可能性是 sizeof(wchar_t) = 2.而且应该注意到标准与现有实践和实际考虑因素相冲突,当理想是标准反而标准化现有实践时,哪里有这样的 .

    现在终于我们能够处理这个问题,

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

    这是一种错误的二分法 . 这两种可能性不是对立的 . 我们有

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

    根据定义

    • sizeof(char) = 1 :它不依赖于系统 .

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

  • 9

    不,没有冲突 . 这两个语句指的是字节的不同定义 .

    UTF-16意味着字节与八位字节相同 - 一组8位 .

    在C语言中,字节与 char 相同 . C -byte可以包含的位数没有限制 . C -byte中的位数由 CHAR_BIT 宏常量定义 .

    如果您的C实现决定使用16位来表示每个字符,则 CHAR_BIT 将为16,并且每个C -byte将占用两个UTF-16字节 . sizeof(char) 仍然是1和所有对象的大小将以16位字节为单位进行测量 .

  • 7

    char被定义为1个字节 . 字节是最小的可寻址单元 . 这在普通系统上是8位,但在某些系统上它是16位,或32位,或其他任何东西(但对于C必须至少为8) .

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

    所以,你的第二和第三个引用是正确的 . 严格来说,第一个引用是不正确的 .

    根据C标准中[intro.memory] / 1的定义, char 只需要能够保存大约100个字符的基本执行字符集(所有这些字符都出现在0 - 127范围的ASCII中),并且构成UTF-8编码的八位字节 . 也许这就是作者对机器字符集的意思 .


    在硬件是八位字节可寻址但字符集是Unicode的系统上, char 可能仍为8位 . 但是,有类型 char16_tchar32_t (在C 11中添加),这些类型设计用于代码而不是 char ,用于具有16位或32位字符集的系统 .

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

    究竟如何处理UTF-16将取决于系统选择的实现细节 . Unicode是一个21位字符集,UTF-16是它的多字节编码;所以系统可以采用类似Windows的路由,并使用 std::basic_string<char16_t> 和字符串的UTF-16编码;或者它可以用原始Unicode代码点作为字符 std::basic_string<char32_t> .

    Alf的帖子详细介绍了可能出现的一些问题 .

  • 5

    没有引用标准,很容易给出简单的答案,因为:

    Definition of byte is not 8 bits . 字节是任何大小但可寻址的最小内存单位 . 最常见的是8位,但没有理由没有16位字节 .

    C标准给出了更多限制,因为它必须至少为8位 .

    因此,无论如何,sizeof(char)始终为1都没有问题 . 有时它会保持8位,有时是16位,依此类推 .

相关问题