C Unicode:如何将 C11 标准修正案 DR488 修复应用于 C11 标准函数 c16rtomb()?



问题:

如该函数的 C 参考页所述,c16rtomb,来自 CPPReference,在注释部分下:

在发布的 C11 中,与将可变宽度多字节(如 UTF-8)转换为可变宽度 16 位(如 UTF-16)编码的mbrtoc16不同,此函数只能转换单单元 16 位编码,这意味着它无法将 UTF-16 转换为 UTF-8,尽管这是此函数的初衷。C11缺陷报告DR488纠正了这一点。

在这段话下面,C 参考页面提供了一个示例源代码,上面有以下句子:

注意:此示例假定应用了缺陷报告 488 的修复程序。

该短语暗示有一种方法可以采用DR488并以某种方式将修复程序"应用于"C11标准功能,c16rtomb

我想知道如何为 GCC 应用修复程序。因为在我看来,从v141开始,该修复程序已经应用于Visual Studio 2017 Visual C++。

在 GDB 中调试代码时,GCC 中出现的行为与 DR488 中的行为一致,如下所示:

第 7.28.1 节描述了函数 c16rtomb()。特别是,它指出"当 c16 不是有效的宽字符时,会发生编码错误"。"宽字符"在第 3.7.3 节中定义为"可由类型 wchar_t 的对象表示的值,能够表示当前区域设置中的任何字符"。这种措辞似乎暗示,例如,对于常见情况(例如,定义__STDC_UTF_16__的实现和使用 UTF-8 语言环境的程序),c16rtomb() 在遇到编码为多个char16_t字符时将返回 -1(对于 UTF-16,宽字符可以编码为由两个char16_t组成的代理项对)。特别是,c16rtomb() 将无法处理 mbrtoc16() 生成的字符串。

粗体文本是所描述的行为。

源代码:

#include <stdio.h>
#include <uchar.h>
#define __STD_UTF_16__
int main() {
char16_t* ptr_string = (char16_t*) u"我是誰";
//C++ disallows variable-length arrays. 
//GCC uses GNUC++, which has a C++ extension for variable length arrays.
//It is not a truly standard feature in C++ pedantic mode at all.
//https://stackoverflow.com/questions/40633344/variable-length-arrays-in-c14
char buffer[64];
char* bufferOut = buffer;
//Must zero this object before attempting to use mbstate_t at all.
mbstate_t multiByteState = {};
//c16 = 16-bit Characters or char16_t typed characters
//r = representation
//tomb = to Multi-Byte Strings
while (*ptr_string) {
char16_t character = *ptr_string;
size_t size = c16rtomb(bufferOut, character, &multiByteState);
if (size == (size_t) -1)
break;
bufferOut += size;
ptr_string++;
}
size_t bufferOutSize = bufferOut - buffer;
printf("Size: %zu - ", bufferOutSize);
for (int i = 0; i < bufferOutSize; i++) {
printf("%#x ", +(unsigned char) buffer[i]);
}
//This statement is used to set a breakpoint. It does not do anything else.
int debug = 0;
return 0;
}

Visual Studio 的输出:

Size: 9 - 0xe6 0x88 0x91 0xe6 0x98 0xaf 0xe8 0xaa 0xb0

海湾合作委员会的输出:

Size: 0 -

在 Linux 中,您应该能够通过调用setlocale(LC_ALL, "en_US.utf8");来解决此问题

关于 ideone 的示例

此函数将执行以下操作,如Microsoft文档中所述:

当前区域设置中将 UTF-16 宽字符转换为多字节字符。

POSIX 文档与此类似。__STD_UTF_16__似乎对任一编译器都没有影响。它应该指定源的编码,应该是 UTF16。它不指定目标的编码。

Windows文档似乎更不一致,因为它似乎暗示setlocale是必要的,或者转换为ANSI代码页是一种选择

最新更新