c32rtomb将编码转换成什么?

21

c32rtombmbrtoc32函数来自于<cuchar>/<uchar.h>,在C Unicode TR(draft)中被描述为在UTF-321和“多字节字符”之间进行转换。

(...) 如果s不是空指针,则c32rtomb函数确定用于表示与给定的宽字符c32相对应的多字节字符(包括任何转义序列)所需的字节数,并将多字节字符表示存储在由s指向的数组的第一个元素中。 (...)

这里的“多字节字符表示”是什么意思?我实际上对以下程序的行为感兴趣:

#include <cassert>
#include <cuchar>
#include <string>

int main() {
    std::u32string u32 = U"this is a wide string";
    std::string narrow  = "this is a wide string";
    std::string converted(1000, '\0');
    char* ptr = &converted[0];
    std::mbstate_t state {};
    for(auto u : u32) {
        ptr += std::c32rtomb(ptr, u, &state);
    }
    converted.resize(ptr - &converted[0]);
    assert(converted == narrow);
}

这个断言是否保证成立1


1 在假设__STDC_UTF_32__被定义的前提下工作。

3个回答

11
为了确保断言成立,必须使用与字符串字面量相同的多字节编码,至少对于实际使用的字符而言,这是 c32rtomb() 所使用的编码。
C99 7.11.1.1/2指定,带类别 LC_CTYPE 的 setlocale() 影响字符处理函数以及多字节和宽字符函数的行为。然而,我没有看到任何明确的确认说明这种影响是设置所使用的多字节和宽字符编码,尽管这是意图。
因此, c32rtomb() 使用的多字节编码是默认"C"语言环境下的多字节编码。
C++11 2.14.3/2指定,执行编码、宽执行编码、UTF-16和UTF-32用于相应的字符和字符串字面量。因此, std::string narrow 使用执行编码来表示该字符串。
那么,该字符串的"C"语言环境编码是否与该字符串的执行编码相同?
C99 7.11.1.1/3 指定"C"语言环境提供C翻译的最小环境。这样的环境不仅包括字符集,还包括使用的特定字符代码。因此,我认为这意味着不仅"C"语言环境必须支持翻译所需的字符(即基本字符集),而且"C"语言环境中这些字符必须使用相同的字符代码。
您字符串字面量中的所有字符都是基本字符集的成员,因此将表示转换为 "C"语言环境表示必须产生与编译器为字符串字面量生成的序列相同的值序列。该断言必须成立。

我没有看到任何建议,表明在执行编码和“C”语言环境之间支持基本字符集之外的任何内容,因此,如果您的字符串文字使用了基本字符集之外的任何字符,则不能保证断言成立。即使规定了存在于执行字符集和“C”语言环境中的扩展字符,我也没有看到任何要求这些表示必须相互匹配。


好的回答。只是为了明确:如果他添加了对setlocale的调用,即使他的字符串完全在基本字符集内,断言也可能失败? - Nemo
1
如果 setlocale() 被调用时参数不是 "C",那么是的。例如,在一个执行编码与 ASCII 兼容的系统上调用 setlocale("en_US.EBCDIC")(假设这是一个带有明显含义的支持区域设置)将导致 c32rtomb() 产生 EBCDIC 字符串,而 std::string narrow 仍然保持 ASCII 编码。 - bames53

5
问题中提到的TR链接说: > 最多存储 MB_CUR_MAX 字节。
这个在C99中被定义为: > 一个正整数表达式,类型为 size_t,是由当前语言环境指定的扩展字符集中多字节字符的最大字节数。
我认为这足以说明 TR 的意图是根据当前安装的 C 语言环境生成多字节字符:对于 en_US.utf8 为 UTF-8,对于 zh_CN.gb18030 为 GB18030 等。

0

经过测试,在Linux/MacOSX中,c32rtomb将字符串从UTF-32转换为特定于区域设置的编码。您可以使用nl_langinfo(CODESET)获取当前使用的编码。

然而,默认情况下,libc使用“C”语言环境,该环境使用ISO-8859-1作为编码。要将编码更改为系统环境指定的编码(通常为UTF-8,但也可能是其他编码),请使用setlocale(LC_CTYPE,“”)。

在Windows中,VS2015+中,c32rtomb始终转换为UTF-8。由于vcruntime不支持UTF-8语言环境(仅支持传统的ANSI / OEM语言环境),如果遵循标准,c32rtomb / c16rtomb将与wcrtomb完全相同,并且没有任何用处。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接