21

函数c32rtombmbrtoc32from <cuchar>/<uchar.h>在 C Unicode TR ( draft ) 中描述为执行 UTF-32 1和“多字节字符”之间的转换。

(...) 如果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__

4

3 回答 3

10

为了保证断言成立,有必要使用的多字节编码c32rtomb()与用于字符串文字的编码相同,至少就字符串中实际使用的字符而言。

C99 7.11.1.1/2 指定setlocale()使用类别LC_CTYPE影响字符处理函数以及多字节和宽字符函数的行为。我没有看到任何明确承认效果是设置使用的多字节和宽字符编码,但这就是目的。

所以使用的多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”语言环境中的那些字符必须使用相同的字符代码。

字符串文字中的所有字符都是基本字符集的成员,因此将char32_t表示转换为“C”语言环境表示必须产生与编译器为字符串文字char产生的相同的值序列;char断言必须成立。

我没有看到任何建议在执行编码和“C”语言环境之间以兼容的方式支持基本字符集之外的任何内容,因此如果您的字符串文字使用了基本字符集之外的任何字符,那么就不会有任何保证断言成立。即使规定了执行字符集和“C”语言环境中都存在的扩展字符,我看不到表示形式相互匹配的任何要求。

于 2012-10-27T00:08:35.807 回答
5

问题中链接的 TR 说

最多MB_CUR_MAX存储字节。

(在 C99 中)定义为

一个正整数表达式,其类型size_t是当前语言环境指定的扩展字符集的多字节字符中的最大字节数

我相信这足以证明 TR 的意图是生成由当前安装的 C 语言环境定义的多字节字符:UTF-8 表示en_US.utf8,GB18030 表示zh_CN.gb18030等。

于 2012-10-24T12:32:18.090 回答
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 完全相同,根本没有用处。

于 2017-03-01T08:45:35.690 回答