char16_t 和 char32_t 字节顺序
char16_t and char32_t endianness
在 C11 中,对可移植宽字符类型 char16_t
和 char32_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_t
和 char32_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_t
和 char32_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_t
或 char32_t
中的代码点值必须具有与 uint_least16_t
和 uint_least32_t
相同的对象表示,因为它们分别定义为这些类型的 typedef
别名 (C11 §7.28)。这又与 C++ 形成对比,C++ 使这些类型不同,但明确要求兼容的对象表示。
结果是,char16_t
和char32_t
没有什么特别的。它们是平台字节序中的普通整数。
但是,您的测试程序与字节序无关。它只是使用宽字符的值,而不检查它们如何映射到内存中的字节。
UTF-16 和 UTF-32 没有定义字节顺序。它们通常以主机本机字节顺序进行编码。这就是为什么可以在字符串的开头插入字节顺序标记 (BOM) 以指示 UTF-16 或 UTF-32 字符串的字节序。
在 C11 中,对可移植宽字符类型 char16_t
和 char32_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_t
和 char32_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
andchar32_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_t
和 char32_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_t
或 char32_t
中的代码点值必须具有与 uint_least16_t
和 uint_least32_t
相同的对象表示,因为它们分别定义为这些类型的 typedef
别名 (C11 §7.28)。这又与 C++ 形成对比,C++ 使这些类型不同,但明确要求兼容的对象表示。
结果是,char16_t
和char32_t
没有什么特别的。它们是平台字节序中的普通整数。
但是,您的测试程序与字节序无关。它只是使用宽字符的值,而不检查它们如何映射到内存中的字节。
UTF-16 和 UTF-32 没有定义字节顺序。它们通常以主机本机字节顺序进行编码。这就是为什么可以在字符串的开头插入字节顺序标记 (BOM) 以指示 UTF-16 或 UTF-32 字符串的字节序。