2012-10-24 16 views
21

機能c32rtombmbrtoc32は、UTF-32 及び "マルチバイト文字" との間の変換を行うようにCユニコードTR(draft)に記載されています。c32rtombはどのようなエンコードに変換しますか? <code><cuchar></code>/<code><uchar.h></code>から

(...)sがヌル ポインタでない場合、c32rtomb関数がシフト配列を含むc32 (によって与えられたワイド文字に対応するマルチバイト文字を 表現するのに必要なバイト数を決定)、によって最初の要素がポイントされている配列を に格納します。 (...)

この「マルチバイト文字表現」とは何ですか?私は、次のプログラムの動作中に実際に興味がある:

#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); 
} 

はそれでアサーションがを保持することが保証されて? __STDC_UTF_32__が定義されているという仮定の下で作業


。問題のリンク

答えて

10

trueを保持するには、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"ロケールの文字が同じ文字コードを使用しなければならないことを意味します。

あなたの文字列リテラル内のすべての文字は、基本文字セットのメンバーであるため、コンパイラはリテラルchar文字列を生成してchar「C」ロケール表現が同じ値のシーケンスを生成しなければならないにchar32_t表現を変換します;主張は真実でなければならない。

実行文字列と "C"ロケールの間で互換性のある方法で基本文字セット以外のものがサポートされているとは思えません。文字列リテラルで基本文字セット以外の文字を使用した場合、アサーションが成立することを保証するものではありません。実行文字セットと "C"ロケールの両方に存在する拡張文字を指定する場合でも、表現がお互いに一致する必要はありません。

+0

ニースの回答。ちょうど明らかである:もし彼が 'setlocale'への呼び出しを追加すると、文字列が基本文字セット内に完全にあってもアサーションは失敗する可能性があります。 – Nemo

+1

@Nemo 'setlocale()'が '" C "'以外の引数で呼び出された場合、yesとなります。実行エンコーディングがASCIIと互換性があるシステムでは、例えば 'setlocale(" en_US.EBCDIC ")'(明白な意味を持つサポートされたロケールであると仮定します)では 'c32rtomb()'がEBCDIC文字列を生成し、 'std :: string 「狭い」はASCII符号化されたままである。 – bames53

5

TRは高々MB_CUR_MAXバイトが格納されている

言います。

現在のロケールで指定された拡張文字セットのマルチバイト文字のバイトの最大数であるタイプsize_t正の整数式として(C99で)定義され

IこれはTRの意図は、現在インストールCロケールによって定義されるようなマルチバイト文字を生成するようにしたことを十分な証拠であると考えて

:UTF-8 en_US.utf8ため、GB18030 zh_CN.gb18030ため、らc。

0

私がテストしたように、Linux/MacOSXでは、c32rtombは文字列をUTF-32からロケール固有のエンコーディングに変換します。 nl_langinfo(CODESET)を使用すると、現在使用されているエンコーディングを取得できます。

しかし、libcはデフォルトで "C"ロケールを使用しており、ISO-8859-1をエンコーディングとして使用します。システム環境が指定するエンコーディングを変更するには、通常はUTF-8が使用されますが、他の場合もあります。setlocale(LC_CTYPE、 "")を使用します。

ただし、VS2015 +では、c32rtombは常にUTF-8に変換されます。 vcruntimeはUTF-8ロケールをサポートしていないため(従来のANSI/OEMロケールのみサポートされています)、標準に準拠すれば、c32rtomb/c16rtombはwcrtombと完全に同一であり、全く使用されません。

関連する問題