char16_t 和 char32_t 字节顺序

char16_t and char32_t endianness

在 C11 中,对可移植宽字符类型 char16_tchar32_t 的支持分别为 UTF-16 和 UTF-32 的 added

然而,在技术报告中,并没有提及这两种类型的字节顺序。

例如,使用 -std=c11 编译时,在我的 x86_64 计算机上 gcc-4.8.4 中的以下片段:

#include <stdio.h>
#include <uchar.h>

char16_t utf16_str[] = u"十六";  // U+5341 U+516D
unsigned char *chars = (unsigned char *) utf16_str;
printf("Bytes: %X %X %X %X\n", chars[0], chars[1], chars[2], chars[3]);

会产生

Bytes: 41 53 6D 51

这意味着它是小端。

但是这种行为是否 platform/implementation 依赖:它是否始终遵守平台的字节顺序,或者某些实现可能选择始终在 big-endian 中实现 char16_tchar32_t

However, in the technical report, there is no mention of endianness for these two types.

确实如此。 C 标准没有详细说明源文件中多字节字符的表示。

char16_t utf16_str[] = u"十六"; // U+5341 U+516D
printf("U+%X U+%X\n", utf_16_str[0], utf_16_str[1]);

will produce U+5341 U+516D Which means that it's little-endian.

But is this behaviour platform/implementation dependent: does it always adhere to the platform's endianness or may some implementation choose to always implement char16_t and char32_t in big-endian?

,如您所说,行为是实现依赖。参见 C11§5.1.1.2:

Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary.

也就是说,您的源代码中的多字节字符是大端还是小端是实现定义的。如果可移植性是个问题,我建议使用 u"\u5341\u516d" 之类的东西。

char16_tchar32_t 不保证 Unicode 编码。 (这是 C++ 的一个特性。)宏 __STDC_UTF_16____STDC_UTF_32__ 分别表示 Unicode 代码点实际上确定了固定大小的字符值。有关这些宏,请参阅 C11 §6.10.8.2。

(顺便说一句,__STDC_ISO_10646__ 表示与 wchar_t 相同的东西,它还揭示了通过 wchar_t 实现的 Unicode 版本。当然,在实践中,编译器只是将源文件中的代码点复制到目标文件中的字符串,因此它不需要了解太多关于特定字符的信息。)

鉴于 Unicode 编码有效,存储在 char16_tchar32_t 中的代码点值必须具有与 uint_least16_tuint_least32_t 相同的对象表示,因为它们分别定义为这些类型的 typedef 别名 (C11 §7.28)。这又与 C++ 形成对比,C++ 使这些类型不同,但明确要求兼容的对象表示。

结果是,char16_tchar32_t没有什么特别的。它们是平台字节序中的普通整数。

但是,您的测试程序与字节序无关。它只是使用宽字符的值,而不检查它们如何映射到内存中的字节。

UTF-16 和 UTF-32 没有定义字节顺序。它们通常以主机本机字节顺序进行编码。这就是为什么可以在字符串的开头插入字节顺序标记 (BOM) 以指示 UTF-16 或 UTF-32 字符串的字节序。