符号なし文字にキャストされたときに、UCHAR_MAXがINT_MAXより大きい{INT_MAX + 1...UCHAR_MAX}の間にある文字値を処理する適切な方法は何ですか。
int is_digit(char c) {
unsigned char uchar = c;
if(uchar > INT_MAX)
return MAYBE;
return isdigit((int)uchar) ? YES : NO;
}
符号なし文字にキャストされたときに、UCHAR_MAXがINT_MAXより大きい{INT_MAX + 1...UCHAR_MAX}の間にある文字値を処理する適切な方法は何ですか。
int is_digit(char c) {
unsigned char uchar = c;
if(uchar > INT_MAX)
return MAYBE;
return isdigit((int)uchar) ? YES : NO;
}
唯一の方法は、マシンにいる場合UCHAR_MAX
よりも大きくなります; つまり、 where には と同じ数のビットがあります。これらのマシンでは、= ≥ .INT_MAX
sizeof(int) == 1
char
int
UCHAR_MAX
UINT_MAX
INT_MAX
32 ビット (またはそれ以上) のマシンでは、これが問題になることはほとんどありません。変数の値がc
テキスト ソースから取得されている限り、オーバーフローを引き起こすことがわかっているテキスト エンコーディングはありません。「UTF-32」でも、下位 21 ビットのみがアクティブになります。(実際には、奇妙なシステムについて話し合っているので、これはsizeof(int)
= 1 かつCHAR_BIT
≥ 22 のマシンで機能すると言わなければなりません ☺)
それでもそのようなマシンでより大きいis_digit()
引数が渡された場合、それはテキスト ソースからのものではありません。未定義の動作は、文字以外のデータを変数に入れることの結果であり、実装が原因ではなく、常にプログラマーが行ったものです。c
INT_MAX
char
これが問題になる可能性があるシステムがあります: 16 ビットchar
およびint
、システムは 16 ビット文字コード (たとえば、UTF-16) を使用し、上位ビットを設定できます。char
そのような場合は、まさにこの理由から、プレーンを署名付きとして定義することが実装に値します。signed を使用char
すると、(signed) に昇格し、関数のファミリにint
安全に渡すことができます。unsigned では、に昇格しis*()
、signed へのキャストは未定義になる可能性があります。char
unsigned
int
int
そのようなシステムでは、コードは確かに壊れていますが、完全に不要な変換と危険な(このシステムでは)キャストに対するあなた自身の責任です。unsigned char
(int)uchar
要約すると、システムでsizeof(int) == 1
は、すべてのコードポイントが変数に格納されている場合、(引数を期待する) 関数char
に安全に渡すことができることを保証する実装の責任があります。これはいつでも実行できます。コードポイントではない変数に何かを格納してそれを渡した場合、未定義の動作の責任はあなたとあなただけにあります。ctype.h
int
char
is*()
Unicode 文字セット (一般的に使用される最大のもの) には、0 から 0x10ffff までの文字コードがあります。そのため、文字コードが INT_MAX よりも大きくなる唯一の可能性int
は、16 ビット タイプ (具体的には 22 ビット未満) の場合です。その場合、単に文字コードを に格納することはできませんint
。
がint
32 ビット型 (または少なくとも 22 ビット) の場合、 にキャストしても文字コードはオーバーフローしませんint
。