C11 では、プレフィックス u8 を持つ新しい文字列リテラルが追加されました。これは、UTF-8 にエンコードされたテキストを含む char の配列を返します。これはどのように可能ですか?通常のcharは署名されていませんか?符号ビットのために、使用する情報が 1 ビット少ないということですか? 私の論理では、UTF-8 テキストの文字列は unsigned char の配列である必要があることを示しています。
4 に答える
ここに潜在的な問題があります:
実装がCHAR_BIT == 8
符号-マグニチュード表現を使用する場合char
(so char
is signed)、UTF-8 が bit-pattern を必要とする場合、それ10000000
は負の 0 です。したがって、実装がさらに負の 0 をサポートしない場合、指定された UTF-8 文字列には無効な (トラップ) 値が含まれている可能性があり、char
問題があります。負のゼロをサポートしている場合でも、ビット パターンが aとビット パターン(ヌル ターミネータ)に10000000
等しいという事実は、 a で UTF-8 データを使用するときに問題を引き起こす可能性があります。char
00000000
char[]
これは、符号付きC11 実装の場合、char
符号なしである必要があることを意味すると思います。通常、char
署名付きか未署名かは実装次第ですが、もちろん、char
署名されているために UTF-8 リテラルを正しく実装できない場合は、実装者は署名なしを選択する必要があります。余談ですが、これは C++ の非 2 の補数実装の場合にずっと当てはまります。C++ ではオブジェクト表現へのアクセスが許可char
されているだけでなく、使用されているからです。unsigned char
C のみが許可されますunsigned char
。
2 の補数と 1 の補数では、UTF-8 データに必要なビット パターンは の有効な値でsigned char
あるため、実装ではchar
符号付きまたは符号なしを自由に作成でき、さらに で UTF-8 文字列を表すことができますchar[]
。これは、すべての 256 ビット パターンが有効な 2 の補数の値であり、UTF-8 がバイト11111111
(1 の補数の負のゼロ) を使用しないためです。
通常のcharは署名されていませんか?
char
であるか であるかはsigned
、実装に依存しunsigned
ます。
さらに、符号ビットは「失われる」わけではなく、情報を表すために引き続き使用でき、char
必ずしも 8 ビットであるとは限りません (一部のプラットフォームではそれよりも大きい場合があります)。
いいえ、それでも符号ビットはビットです! また、UTF-8 仕様自体は、文字が符号なしでなければならないとは言っていません。
PS Wat is kookwekker voor 'n naam?
char の符号は重要ではありません。utf8 はシフト操作とマスク操作のみで処理できます (signed 型では面倒かもしれませんが、不可能ではありません)。
ポイントごとに説明すると、次のフラグメントには、文字の値に対する算術演算が含まれておらず、シフトとマスクのみが含まれています。
static int eat_utf8(unsigned char *str, unsigned len, unsigned *target)
{
unsigned val = 0;
unsigned todo;
if (!len) return 0;
val = str[0];
if ((val & 0x80) == 0x00) { if (target) *target = val; return 1; }
else if ((val & 0xe0) == 0xc0) { val &= 0x1f; todo = 1; }
else if ((val & 0xf0) == 0xe0) { val &= 0x0f; todo = 2; }
else if ((val & 0xf8) == 0xf0) { val &= 0x07; todo = 3; }
else if ((val & 0xfc) == 0xf8) { val &= 0x03; todo = 4; }
else if ((val & 0xfe) == 0xfc) { val &= 0x01; todo = 5; }
else { /* Default (Not in the spec) */
if (target) *target = val;
return -1; }
len--;str++;
if (todo > len) { return -todo; }
for(len=todo;todo--;) {
/* For validity checking we should also
** test if ((*str & 0xc0) == 0x80) here */
val <<= 6;
val |= *str++ & 0x3f;
}
if (target) *target = val;
return 1+ len;
}