6

mbrtowc(マルチバイト文字ポインター) 引数のポインターを次NULLのように処理するように指定されています。s

s がヌル ポインターの場合、mbrtowc() 関数は次の呼び出しと同等になります。

mbrtowc(NULL, "", 1, ps)

この場合、引数 pwc と n の値は無視されます。

私が知る限り、この使用法はほとんど役に立ちません。が部分的に変換された文字を格納していない場合ps、呼び出しは副作用なしで単に 0 を返します。psが部分的に変換された文字を格納している場合'\0'、 はマルチバイト シーケンスの次のバイトとして有効ではないため ('\0'文字列ターミネータのみを指定できます)、呼び出しは を返し(size_t)-1ますerrno==EILSEQps未定義の状態のままにします。

意図された使用法は、状態変数をリセットすることだったようです。特にNULLが渡され、内部状態が使用された場合、ステートフル エンコーディングでの の動作psに似ていますが、これは私が知る限りどこにも指定されていません。部分的に変換された文字の のストレージのセマンティクスと競合します (潜在的に有効な初期サブシーケンスの後に 0 バイトに遭遇したときに状態をリセットすると、この危険で無効なシーケンスを検出できなくなります)。mbtowcmbrtowcmbrtowc

が の場合mbrtowcにのみ状態変数をリセットするように指定されていて、それが 0 バイトを指している場合sNULLそうでない場合、望ましい状態リセット動作は可能ですが、そのような動作は書かれている標準に違反します。これは規格の欠陥ですか?私が知る限り、不正なシーケンスに遭遇すると内部状態 ( is の場合に使用) をリセットする方法はまったくないため、正しいプログラムは を使用できpsません。NULLmbrtowcps==NULL

4

2 に答える 2

5

'\0' バイトは、シフト状態 (5.2.1.2 マルチバイト文字) に関係なくヌル ワイド文字に変換する必要がありmbrtowc()、ワイド ヌル文字 (7.24.6.3.2 /3 mbrtowc 関数) を呼び出すと、 が指す にmbrtowc( NULL, "", 1, ps)格納されているシフト状態がリセットさmbstate_tpsます。mbrtowc( NULL, "", 1, NULL)ライブラリの内部オブジェクトを使用するために が呼び出されると、mbstate_t初期状態にリセットされます。標準の関連ビットの引用については、回答の最後を参照してください。

私は、C 標準のマルチバイト変換関数について特別な経験があるわけではありません (この種の経験では、変換に Win32 API を使用しています)。

mbrtowc()0バイトで短くカットされた「不完全な文字」を処理する場合(size_t)(-1)、無効なマルチバイト文字を示すために返されます(したがって、説明する危険な状況を検出します)。その場合、変換/シフト状態は指定されていません (そして、基本的にその文字列にうんざりしていると思います)。変換が試みられたが を含むマルチバイトの「シーケンス」'\0'は無効であり、後続のデータで有効になります。'\0' が変換されたシーケンスの一部であることが意図されていない場合、処理に使用できるバイト数に含まれるべきではありません。

部分的なマルチバイト文字 (ネットワーク ストリームなど) の追加の後続のバイトを取得する可能性がある状況にある場合、部分的なマルチバイト文字nに渡したものに 0 バイトを含めないでください。(size_t)(-2)戻ってきた。この場合、'\0'部分変換の途中でしばらく経過すると、エラーが発生したという事実が失われ、副作用として使用中のmbstate_t状態がリセットされます (使用中の状態が自分のものであるか、使用されている内部のものであるかに関係なく)。に NULL ポインターを渡しましたps)。私は本質的にここであなたの質問を言い直していると思います。

ただし、この状況を検出して処理することは可能だと思いますが、残念ながら、自分で状態を追跡する必要があります。

#define MB_ERROR    ((size_t)(-1))
#define MB_PARTIAL  ((size_t)(-2))

// function to get a stream of multibyte characters from somewhere
int get_next(void);

int bar(void)
{
    char c;
    wchar_t wc;
    mbstate_t state = {0};

    int in_partial_convert = 0;

    while ((c = get_next()) != EOF)
    {
        size_t result = mbrtowc( &wc, &c, 1, &state);

        switch (result) {
        case MB_ERROR:
            // this multibyte char is invalid
            return -1;
        case MB_PARTIAL:
            // do nothing yet, we need more data
            // but remember that we're in this state
            in_partial_convert = 1;
            break;
        case 1:
            // output the competed wide char
            in_partial_convert = 0;     // no longer in the middle of a conversion
            putwchar(wc);
            break;
        case 0:
            if (in_partial_convert) {
                // this 'last' multibyte char was mal-formed
                // return an error condidtion
                return -1;
            }
            // end of the multibyte string
            // we'll handle similar to EOF
            return 0;
        }
    }

    return 0;
}

理想的な状況ではないかもしれませんが、完全に壊れていて使えないわけではないことを示していると思います。


規格の引用:

5.2.1.2 マルチバイト文字

  • マルチバイト文字セットには、状態依存のエンコーディングが含まれる場合があります。この場合、マルチバイト文字の各シーケンスは初期シフト状態で始まり、特定のマルチバイト文字がシーケンス内で検出されると、他のロケール固有のシフト状態に入ります。初期シフト状態の間、すべてのシングルバイト文字は通常の解釈を保持し、シフト状態を変更しません。シーケンス内の後続のバイトの解釈は、現在のシフト状態の関数です。

  • すべてのビットがゼロのバイトは、シフト状態に関係なくヌル文字として解釈されます。

  • すべてのビットが 0 のバイトは、マルチバイト文字の 2 番目以降のバイトには出現しません。

7.24.6.3.2/3 mbrtowc 関数

対応するワイド文字がヌル ワイド文字の場合、記述されている結果の状態は初期変換状態です。

于 2011-01-17T06:35:48.900 に答える
1

5.2.1.2 のマルチバイト文字では、C 標準は次のように述べています。

すべてのビットがゼロのバイトは、シフト状態に関係なくヌル文字として解釈されます。そのようなバイトは、他のマルチバイト文字の一部として発生してはなりません。

たとえば、7.24.6で言及されているように、標準はシフト状態と変換状態を区別しているようです。

ポイントされたオブジェクトによって記述された変換状態は、関連付けられたマルチバイト文字シーケンスのシフト状態とマルチバイト文字内の位置を追跡するために、必要に応じて変更されます。

(強調は私が追加しました)。ただし、特に「そのようなバイトは、他のマルチバイト文字の一部として発生してはならない」など、変換状態全体をエンコードする mbstate_t 値に関係なく、すべてのビットがゼロのバイトをヌル文字として解釈することが意図されていると思います。マルチバイト文字内でヌルバイトが発生できないことを意味します。マルチバイト文字の 2 番目、3 番目などのバイトが存在するはずの間違った入力でnull バイト発生した場合、標準は、EOF の部分的なマルチバイト文字が黙って無視されると言っていると解釈します。

私の 7.24.6.3.2 の読み方は、mbrtowc次の 1 バイトが null ワイド文字を完了し、戻り値が 0 であり、結果の状態が初期変換状態であるためです。sNULLmbrtowc

対応するワイド文字がヌル ワイド文字である場合、記述されている結果の状態は初期変換状態です。

NULLと の両方sを渡すことによりps、 の内部 mbstate_t がmbrtowc初期状態にリセットされます。

于 2011-01-25T22:14:12.360 に答える