|
|
|
| 2008/10/07 11:46||▲
|
|
|
今回は、処理系の特性を把握する目的を兼ねて、<limits.h>の実装についてお話します。<limits.h>は、主として、整数型の限界値を表すマクロを定義するためのものです。それぞれのマクロは、#if指令で使用するのに適した形式でなければなりません。すなわち、マクロの定義内容に、キャストやsizeofといった演算子を使うことはできません。
それでは、MB_LEN_MAXからです。MB_LEN_MXマクロは、処理系がサポートしている最大の多バイト文字のバイト数を表します。gccではUTF-8がサポートされていますので、本来であれば6に設定すべきですが、UCS-2の範囲で十分なので3とします。なお、gccはISO-2022-JPもサポートしていますが、シフトシーケンスに依存するエンコーディングは、利用価値が低い上に実装も面倒なので非サポートとします。というわけで、
#define MB_LEN_MAX 3
ということにします。3あれば、シフトJISやEUCを扱う上でも十分です。
次に、CHAR_BITですが、これはchar型を構成するビット数を表します。C言語では、char型のサイズが1バイトですので、sizeof演算子で得られる値も、このchar型のサイズが基準となります。"h8300-hms"ターゲットのgccでは、char型は8ビットですので、CHAR_BITは8に定義します。
#define CHAR_BIT 8
さて、いよいよ整数型の最大最小値に入ります。まずは、signed char型の最大最小値を表すSCHAR_MAXとSCHA_MINです。signed char型もchar型同様8ビットであり、負の値は2の補数を使って表現しますので、
#define SCHAR_MAX 127 #define SCHAR_MIN (-128)
となります。SCHAR_MINの定義は括弧でくくっておかないと、1-SCHAR_MINのように記述したとき、コンパイルオプションによっては、1--128のように展開されるので、"--"が減分演算子だとコンパイラが誤認してしまいます。
続いて、unsigned char型の最大値を表すUCHAR_MAXです。符号なし整数型の最小値は 0 に決まっているので、マクロはありません。unsigned char型も8ビットですので、UCHAR_MAXは255になります。
#define UCHAR_MAX 255
次は、char型の最大最小値を表すCHAR_MAXとCHAR_MINですが、char型は、コンパイルオプションによって、符号付きにも符号なしにもなりますから、どんなコンパイルオプションが指定されたかを知る必要があります。gccの場合、char型が符号なしの場合には、__CHAR_UNSIGNED__というマクロが予め定義されます。#ifdefまたは#ifndef指令を使って、判別することができそうです。
#ifndef __CHAR_UNSIGNED__ #define CHAR_MAX SCHAR_MAX #define CHAR_MIN SCHAR_MIN #else #define CHAR_MAX UCHAR_MAX #define CHAR_MIN 0 #endif
小さい型から順に解説していってますので、次はshort型の番です。"h8300-hms"ターゲットのgccでは、short型は16ビットです。ただし、int型が16ビットか32ビットかはコンパイルオプションに依存します。short型の話をしているのに、なぜint型が関係あるのかと思われるかもしれませんが、実は大ありなのです。
<limits.h>で定義すべき最大最小値のマクロは、その型のオブジェクトのみで構成される式が汎整数拡張されたときの型と同じ型に評価されなければなりません。例えば、SHRT_MINを安易に(-32768)と定義してしまうと、int型が16ビットの場合、32768はint型の範囲を超えているので、long型になってしまいます。long型の定数に符号演算子 - を付けてもlong型のままです。これでは規格に合致しません。
というわけで、SHRT_MAXおよびSHRT_MINは次のように定義します。
#define SHRT_MAX 32767 #define SHRT_MIN (-32767-1)
(-32767-1)とすることで、例えint型が16ビットでも32767はint型の範囲におさまりますからint型になります。1もint型ですので、int型どうしの演算もやはりint型になります。
同様の理由で、unsigned char型の最大値であるUSHRT_MAXも65535とすることはできません。そこで、
#define USHRT_MAX 0xffff
とします。10進定数は、int型の範囲を超えるとlong型になりますが、8進または16進定数は、int型の範囲を超えると、まずunsigned int型になります。したがって0xffffは、int型が16ビットであればunsigned int型に、int型が32ビットであればint型に評価されることになります。
ところで、unsigned short型が汎整数拡張された場合ですが、int > shortの場合はunsigned int型ではなくint型になります。汎整数昇格が起きた場合、値は保存されますが、型の符号の有無は保存されないのです。
続いてint型ですが、これもchar型と同じく、コンパイルオプションに依存しますので、普通なら場合分けが必要です。しかし、"h8300-hms"ターゲットのgccでは、__INT_MAX__というマクロが予め定義されます。これを利用すると、
#define INT_MAX __INT_MAX__ #define INT_MIN (-__INT_MAX__-1)
と書くことができます。
unsigned int型の最大値を表すUINT_MAXにも__INT_MAX__を使うことができそうです。ただし、最終的な型をunsigned int型にする仕組みも必要です。
#define UINT_MAX (__INT_MAX__*2U+1)
簡単に解説すると、__INT_MAX__が32767の場合、2倍することで、65534になります。ここで、単なる 2 ではなく、2U を掛けているので、その時点でunsigned int型になります。そして、65534U+1で65535Uを作っています。
long型とlong long型についても、__LONG_MAX__および__LONG_LONG_MAX__というマクロが予め定義されていますので、これらを使って、
#define LONG_MAX __LONG_MAX__ #define LONG_MIN (-__LONG_MAX__-1) #define ULONG_MAX (__LONG_MAX__*2UL+1)
#define LLONG_MAX __LONG_LONG_MAX__ #define LLONG_MIN (-__LONG_LONG_MAX__-1) #define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1)
と書くことができます。
|
| 2006/01/24 14:48|処理系の特性|TB:0|CM:4|▲
|
|
|
コメント
|
最新の Unicode では、UTF-8 は 4 バイトまでに短縮されてます。これは UTF-16 で扱えるコードポイントに制限したためです。アラインメントのことも考え合わせれば、MB_LEN_MAX は 4 にしちまうのがよいのではなかろうかと思います。
|
通りすがり #-|2006/01/24(火) 15:27 [ 編集 ]
|
ご指摘ありがとうございます。
MB_LEN_MAXですが、実際の用途を考えると、ナル文字分を付加してMB_LEN_MAX+1、または多バイト文字列用にMB_LEN_MAX*N+1とする場合が結構あると思います。
MB_CUR_MAXは整数定数式ではないので、(可変長配列を避けるには)配列要素にはMB_LEN_MAXを使うしかないので、諸々のことを考えると、少しでも小さい方がスタック消費が少なくて済むと思うのです。
これについては、もう少し検討してみます。
|
たかぎ #ftr86F3A|2006/01/24(火) 16:25 [ 編集 ]
|
このコメントは管理人のみ閲覧できます
|
#|2006/01/24(火) 17:48 [ 編集 ]
|
1-SCHAR_MINは1- -128のように空白文字が入るので、--とは誤認されないとの指摘を受けました。 誤認されるのは、-traditionalオプションを付けて前処理を行った場合だけですので、本文を一部修正しました。
|
たかぎ #ftr86F3A|2006/01/24(火) 18:25 [ 編集 ]
| |
コメントの投稿
| |
|
| |
トラックバック
|
トラックバックURLはこちら
http://libc.blog47.fc2.com/tb.php/10-7264b4cf
|
| |
|
|
ホーム
全記事一覧
<< 前の記事
次の記事 >>
|
| | | |