アルゴリズム 0 テータ構造入門 ロックアドレス 113 ) に含まれるのて、 , その プロックをバッフアに読み込みます。そし て , そのノヾッフアの 476 ~ 495 バイト目の 20 バイトをユーザが指定した領域にコピーし ます。 また複数のプロックにまたがる場合には , この手順を繰り返し行うことになります。 ファイルの先頭から 800 バイト目から 2299 バ イト目の合計 1500 バイトを読み込む例を Fi g. 4 に示しましよう。 書き込みの手順は , 読み出しの手順とほ とんど同じて、す。しかし , そのプロックを あらかじめバッフアに読み込んて、から , バ ッファ ~ 書き込むデータをコピーして , 最 後にプロックをディスクに書き戻すという 3 段階の手順が必要になります。 こて、は , ファイ Fig. 5 を見てください ルの先頭から 1500 バイト目から 20 バイト分 のデータを書き込もうとしています。まず 最初に , 1 番目のプロック ( プロックアドレ ス 113 ) を丸ごとバッフアへ読み込みます (F ig. 5 ー① ) 。次に , 与・えられた 20 バイトのデ ータをバッフアの所定の位置 ( 476 ~ 495 バイ トめ ) にコピーします (Fig. 5 ー② ) 。そして , バッフアの内容をプロックアドレ 最後に ス 113 に書き戻します ( Fig. 5 ー③ ) 。 こて、 , 1 番目のプロックに含まれていて , 書き込み が行われない部分 ( Fig. 5 ー②の横線を引いた 部分 ) の値を保存するために , あらかじめプ ロックをバッフアに読み込まなければなら ないことに注意しましよう。もし , Fig. 5 ー ①の手順を省いてしまうと , この部分にゴ ミのデータが書き込まれてしまうことにな ります。もちろん , 1 プロック分をまるごと 書き込む場合には , Fig. 5- ①の処理は不要 て、す。 バッファリングという技法 このように を用いれば , 本来ならプロック単位て、しか 読み書きがて、きないプロックデバイスても バイト単位て、の読み書きが可能になります。 ティスクのキャッシンク、 ところて、 , 今まて、に説明した方式て、は , 読み書きの要求があるごとに ノヾッフア領 域とディスクの間て、必ず 1 回はデータを転送 する必要があります。しかし , 実際には , ファイルへの読み書きは , 連続した位置に 対して行われるのが普通て、 , この場合には , 同じプロックを何度も繰り返し読み込むこ とになります。 たとえば , Fig. 2 のファイルを 512 バイト ずっ順番に読み込んて、いくことを考えまし よう (Fig. 6 ) 。この場合には , まず先頭のプ ロックをバッフアに読み込んて、 , その前半 512 バイトをユーザの指定した領域にコヒ。ー します (Fig. 6 ー① ) 。次に , 再び先頭のプロ Fig. 5 ファイルへの書き込みファイルの 1500 ノヾイト 目から 20 バイト分のテータを書き込む 52 24 25 113 ファイル 八ッファ 書き込む ① 1 番目のプロックをバッフアに読み込む 47 47 ファイル バッファ 書き込む テータ コピーする ファイル 八ッファ 52 113 24 25 書き込むテータをバッフア内の所定の位置 ( 476 ~ 495 バイト目 ) に 52 113 24 25 47 書き込む ③バッフアの内容を 1 番目のプロックに書き込む ファイルの読み込み時のムダなティスク入力の回避 ファイル ↓ バッファ ユーザが指 定した領域 ①先頭のプロックをバッフアに読み込んでから前半の 512 バイトを 指定された領域にコピーする ↓ ファイル ↓ バッファ ユーサが指 定した領域 再び先頭のプロックをバッフアに読み込んて後半の 512 バイトを コピーする ファイル バッファ ユーザが指 定した領域 ③すでに先頭のフロックがノヾッフアに読み込まれている バッフアの後半 512 バイトをコピーする アルゴリズムとデータ構造入門 63
ャラクタデバイスかの区別 ) を , プログラム が意識する必要はありません。また , 反対に いえば , このようにソフトウェアから見た I / O 装置の扱いが統一されているからこそ , 入出力のリダイレクトやパイプラインがサ ポートて、きるのて、す。 プロックデバイスから , 任意の長さのデ ータを読み出すことを考えましよう。前回 , 少し触れたようにプロックデバイスを扱う 場合 , ファイルはプロック単位て、割り当て が行われます。たとえ大きさが 1 バイトのフ ァイルて、も , ディスク上て、はまるまる 1 プロ こて、は , 1 プロックの ックを占有します。 大きさがちょうど IK バイト ( 1024 バイト ) に なっているものとして話を進めましよう。 ファイルはプロックの集まりとして表現 されます。また , ディスク上のプロックに は , プロック番号が振られています。プロ ックの読み書きは , プロック番号 ( または , CPU Fig. 1 キャッシュメモリ プロックアドレスともいう ) を指定して行い ます ( 実際には , ディスクのアクセスは , シ リンダ番号 , ヘッド番号 , セクタ番号を指 定して行いますが , 話を単純にするために プロック番号て、プロックの指定を行うこと にします ) 。 Fig. 2 のようにプロックを割り当てたファ イルを考えてみましよう。先頭から順に プロック番号が 52 , 113 , 24 , 25 , 47 , 18 に なっています。ファイルの先頭から 1023 バ イト目まて、はプロック番号 52 に , 1024 ~ 20 47 バイト目はプロック番号 113 に , 2048 ~ 3 071 バイト目まてはプロック番号 24 に , とい う具合に対応しています。一般に先頭から k バイト目のデータは , k / 1024 番目のプロッ ク ( ただし , 小数点以下は切り捨て ) の先頭 から k% 1024 バイト目に位置します。 て、 , 先頭のプロックは 0 番目として数えてい ることに注意してください。たとえば , 15 00 バイト目のデータは , 1 番目のプロック (Fig. 2 て、いえば , プロック番号が 113 ) の 47 6 バイト目に対応しています。 基本的には , 目的のデータが含まれるプ ロックを読み込んて、 , そのうちに実際に必 要になる部分だけを読み込み領域にコヒ。ー するという方針て、いきます。 こて、 , 読み 込みはプロック単位てしか実行て、きません から , 1 プロック分のデータが入るだけの / ヾ ッファ ( 作業領域 ) を用意しておいて , ディ スクからプロック長のデータをノヾッフアに 読み込んて、から , そのうちの指定されたバ イトだけをユーザが指定した領域にコピー します。これをバッファリング ( bufferring ) といいます。 例として , ファイルの先頭から 1500 バイ ト目から 20 バイトを読み出すことを考えて みましよう (Fig. 3 ) 。 1500 バイト目のデータ は , 先ほど見たように 1 番目のプロック ( プ Fig. 4 複数のフ、ロックにまたがる読み込み ファイルの 800 バイト目から 1500 ノヾイトを読み込む CPU アクセス時間 30nsec 52 113 24 25 47 ファイル ↓ 18 キャッシュメモリ アクセス時間 60nsec アクセス時間 60nsec メモリ メモリ (a) キャッシュメモリなしのシステム (b) キャッシュメモリつきのシステム Fig. 2 ファイルのプロック割り当て 0 1024 2048 3072 4096 5120 6144 52 0 113 1 24 2 2 5 3 24 47 4 25 ( バイト ) ( プロック ) Fig. 3 ファイルの読み込み 5 47 ファイル バッファ ユーザが 指定した 領域 62 C MAGAZINE 52 113 1992 6 ・ファイルの 1500 ノヾイト目から 20 バイト読み込む バッファ ユーザか 指定した 領域 ① 0 番目のプロックをバッフアに読み込み , バッフアの 800 ~ 1023 ノヾイ ト目をコピーする ファイル 2 5 52 24 47 113 八ッファ ユーサが指 定した領域 をコピーする ③ 2 番目のプロックをバッフアに読み込み , バッフアの 0 ~ 251 八イト目 定した領域 ユーサが指 バッファ 113 47 2 5 24 52 ファイル 01 番目のプロックをノヾッフアに読み込み , バッフア全体をコピーする
三 JIS C 概観 TabIe 2 the Standard C で新しく導入されたマッピングのための関数 関数 int mblen(const char * , size t) int mbtowc(wchar t * , const cha 「 * , size t) int wctomb(char * , wcha 「 t) size t mbstowcs(wchar t * , const char * , size t) size t wcstombs(char * , const wchar t * , size t) , 多バイト文字 1 文字分のバイト数を返す 内容 ワイド文字列を多バイト文字列に一括変換する 多バイト文字列をワイド文字列に一括変換する ワイド文字 1 文字を多八イト文字 1 文字に変換する 多バイト文字 1 文字をワイド文字 1 文字に変換する さのワイド文字にマッヒ。ングされる。マッヒ。 ングは , theStandardC て、新しく導入された Table 2 に示す関数によって行われる。これ らの関数名て、 , 、、 mb 〃は , 多バイト文字 ( mu ltibyte character) を表し , 、、 wc クは , ワイ ド文字 (wide character) を表している。 言語仕様面て、も , Fig. 6 のような記述が このようなライプラリが追加されたと同時 ワイド文字列定数 例 ) L' 字 ,, L'a' ワイド文字定数 Fig. 6 言語仕様面可能になった記述 これらの新しい機能を用いたテキスト処理 7 に示しておく。 列とワイド文字列とのマッヒ。ングの例を Fig. ed short) て、 typedef した場合の多バイト文字 wcahr t を 2 バイトの型 ( たとえば , unsign 可能となった。 の概念は , Fig. 8 のようになる。 Fig. 8 て、示す , 「ワイド文字列の加工」の部 分は , 「 1 文字 = = 1 バイト」て、ある ASCII の 世界て、のテキスト処理と同じロジックがその まま適用て、きる。ワイド文字単位て、処理を行 うなら , もはや , プログラム中て、 , シフトシ ーケンスを生に意識したり , 2 バイトコード の片割れを意識したりする必要性はないのて、 ある。 ただし , 先ほどの筆者の文字化け修復プロ グラムて、は , 元々不正な文字コードの入力を 仮定している特殊な場合て、あるため , このよ うなワイド文字べースのプログラムに置き換 えるわけにはいかない 現規格での問題点 数て指定される書式文字列を多バイト文字列 現規格て、は , 処理系は , printf( ) の第一引 p 「 intf( ) の問題 て、ある。 まず , 間題になるのが , printf(), scanf() て、ある。 的なプログラムを記述するにはまだまだ不足 が導入されてはいるが , これだけて、は , 実用 ardC て、は , 多バイト文字処理のための機構 以上 , 簡単に説明したように , theStand 例 ) L"this is ワイド文字列 " wchar t 型配列の初期化 例 ) #include く stddef. h> wchar t buff [ ] L"this is 漢字 " Fig. 7 多バイト文字列とワイド文字列とのマッピングの例 多バイト文字列 "a 日 x" 'a' シフトイン シフトアウト 0X61 OXIB 0X24 0X42 0X46 0X7C OXIB 0X28 0X4A 0X78 0X00 mbstowcs( ) ↓ wcstombs( ) ↑ L' 日 ' L L'YO' 0X00 0X61 0XA4 0XC2 0X00 0X78 0X00 0X00 ワイド文字列 L ” a 日 x ” Fig. 8 新しい機能を用いたテキスト処理の概念 漢字を含むテキストファイ丿い getchar( ) , getc( ) , fgtec( ) 入力 gets( ) , fgets( ) メモリ char buffC ] ; 変換 mbtowc( ) , mbstowcs( ) # include く stddef. h 〉 メモリ wchar—t buffC ] ; wchar—t*wp = &buffCO] ; ワイド文字列の加工 変換 wctomb( ) , wcstomb( ) メモリ char buffC ] ; putchar( ) , putc( ) , fputc( ) 出力 puts( ) , fputs( ) 漢字を含むテキストファイ朋 特集第 3 の標準』 S C 概観 43
eaplen と stklen に初期値を設定することに より , near ヒープ領域とスタック領域のサ イズを設定するのて、 , TINY モデルのほうが消 費するメモリを少なくすることがて、きます。 プログラムか獲得する メモリサイズ それて、はちょっと脇道にそれてプログラ ムが穫得するメモリサイズについて少し考 えてみましよう。たとえば , List 1 (listl. c) のように子プロセスを起動するプログラム の場合 , 子プロセスにて、きるだけ多くのメ モリを割り当てたいものて、す。 MS-C 6.0 て、の List 1 の実行例を Fig. 5 に 示します。最初 ( ① ) は通常のユーザがコン この 7 以 112fhX10h バイト 68.7K バイト 時 , ②を見るとプログラムサイズは とデフォルトの設定になっています。 スタックサイズ = 2K バイト MAXALLOC=FFFFh パイルした状態て、 80 C MAGAZINE 1992 6 MS-C て、は EXEHDR/EXEMOD コマンド となっています。 45chX10h バイト 17.4K バイト 増加し イズが増やしたスタックサイズのぶんだけ LLOC も変更され , ⑧を見ればプログラムサ 10K バイトに設定すると⑦のように MAXA ⑥て、スタックサイズを 8K バイト増やして あるて、しよう。 プログラムによっては無視て、きない場合も の意味」参照 ) 。この約 60K バイト弱もの差は と激減しています ( コラム「 exehdr/max : 1 25chX10h/\+ イト 9 4K バイト すると ( ④ ) , ⑤のようにプログラムサイズは 設定するため , MAXALLOC を最小値に設定 ③て、 near ヒープ領域のサイズを 0 バイトに されているため , このようになります。 メントのサイズが最大限の 64K バイトに設定 は非常に大きなサイズて、すが , データセグ となっています。小さなプログラムにして て、簡単に変更て、きますが , Turbo C 2.0 / C 十十 1.0 て、は heaplen と stklen に初期値 を設定することにより , Fig. 5 と同様なこと を確認することがて、きます。 上記のことを考えれば MS-LINK(LINK. EXE) のスイッチて、 /stack (/st) /cparmaxalloc (/cp) を設定する ( Turb0C 2.0 / C 十十 1 . 0 て、は heaplen と stklen に初期値を設定する ) こ とは十分に意味のあることだとおわかりに なると思います ( コラム「 COM モデルと EXE モデルのメモリサイズ」参照 ) 。 スタックの消費量を 調べる方法 本題に戻って , スタックの消費量を調へ る方法を考えてみましよう。筆者がたちま ち思いつく方法は次の三つて、す。 ①スタック領域の初期値を 00h , 0FFh などの 値に設定しておき , 終了時にスタック領 域の値を調べ , 使用スタック量を知る ②コンパイラはスタックチェックを行うコ ードを生成するスイッチを持っている。 このスタックチェックは関数呼び出しに なっている処理系が多く , スタックチェ ックの関数を自作してやれば , その時点 でのスタックポインタの値を取得できる 7 List 2 をスタックチェックを行うモードて、 コンパイルしたアセンプリリストを List 2A —List 2E に示します。 これらをみれば MS ー C と LSIC には , この 方法が適用可能てすが , Tub0 C 2.0 / C 十十 1.0 て、はスタックチェックを行うコードがイ ンライン展開されるため , 適用て、きない とがわかります。 この方法には呼び出したライプラリ関数 が使用するスタック量を調べることがて、き ないという欠点があります ( ライプラリ関数 がスタックチェックの関数を呼び出してい れば調べることはて、きますが , ほとんどの ライプラリ関数はスタックチェックの関数 を呼び出していません ) 。 ③プログラム実行中に定期的にスタックポ インタの値を調べる。本当はタイマ割り 込みなどのハードウェア割り込みに割り 込んで , 定期的に ss : SP をサンプリング して調べるのが効果的だが , 結構めんど うだから , DOS ファンクションの爪 T 21 h に割り込んで , その時点でのスタックポ インタの値を調べるという手抜きの方法 も考えられる DOS ファンクションを呼び出さない関数 は調べられないという欠点がありますが , qsort などの再帰関数を除くと , スタックを 多く消費するライプラリの大半は DOS ファ 。 , ム exehd 「 /max : 1 の意味 exehdr /max : 1 list2 のように MAXALLOC を 1 に設定しても , 最低 限必要な ヒープ領域の大きさが 0 バイトとなります す。このように設定すると起動時には near の合計サイズ ( M 爪 ALLOC ) に設定されま ②スタック領域 ①初期化されていないデータ領域 が , MS ー C ではスタートアップルーチンが環 境変数領域や main 関数の引数を設定するた めに最低限の near ヒープ領域を確保します。 なお , LSI C ver 3.20 でこのような設定 を行うとスタートアップルーチンが対応し ていないため , EXE ファイルを実行したとき に暴走してしまう場合があります。
として解釈することが義務づけられている。 これは , たとえ漢字コードの中に , 変換指定 子を表わす 1 バイトの、、 % クと同じコードか凸 まれていたとしても , 処理系は , そのコードを 2 バイトの漢字コードの中のものて、あると認 識し , 誤動作することはないことを保障して いる。そこまて、は , いいとしよう。 問題は , % s 変換における「フィールド幅」 と「精度」て、ある。これは , 現規格て、は , バイ ト単位て、しか指定て、きない。しかもそれは , 処理データのメモリ中のバイト数て、あって , 画面やプリンタへの出力結果における印字幅 や出力幅単位て、はないのて、ある。これは , プ ログラマが , 各文字が処理データとしてメモ リ中て、何バイトを占めるか , あるいは , それ らが印字された場合 , どれくらいの幅を占め るか , ということをよく知っていなければな らないことを意味している。 さらに こて、もまた , シフトコードが混 入している場合 , 問題は , より複雑になる。 データのどこにシフトコードが入っている か , ということを一般のプログラマは関知し ていないからて、ある。しかし , そのシフトコ ードのバイト数も意識して「フィールド幅」や 「精度」を指定しなくていけないのて、ある。そ のようにあらわに文字のバイト数や出力幅を 意識してコーディングしてあるプログラムを 無修正て、別のコード系を採用している処理系 に持っていき正常動作させることはて、きな また , printf ( ) の出力結果のなかにも予期 Fig. 9 日本語化に関するプロジェクト , 委員会 せざるシフトコードが混入するて、あろう。 s printf() て、は , どれくらいの長さの出力バッ フアを用意したらよいのか予測しがたい scanf ( ) の問題 複数文字集合の問題 複数ストリーム る文字列の「シフト状態」 (shift state) を保持 mbtowc( ) , wctomb( ) は , 現在処理してい しておかなくてはいけない状況に似ている。 が現在処理している文字列のポインタを保持 処理て、きない。それは , ちょうど , strtok ( ) は , 残念ながら , 一度にひとつの文字列しか wc ( ) および wctomb ( ) の変換ライプラリ the Standard C て、新しく導入された mbto いて、あろう。 える。使いものにならないと思ったほうがよ 動作は , 一般に何が起きるかわからないとい 多バイト文字列に anf ( ) を適用した場合の 点があるが , 詳細な考察は省略する。要は , るからて、ある。これ以外にもさまざまな問題 い位置にシフトコードが混入してしまってい 式文字列のなかには , プログラマが関知しな 雑にする。プログラマがコーディングした書 こて、もまたシフトコードがものごとを複 チングて、ある。 ータとしての文字列の「バイト単位」て、のマッ ログラマが指定した書式文字列と , 実行時デ も深刻て、ある。 scanf( ) の動作の基本は , プ scnaf( ) の間題は , さらに , printf( ) より しておかなくてはいけないからて、ある。 , こて、いう「シフト状態」とは , たとえば , ある位置のバイトデータが 1 バイト文字に対 応するものて、あるのか , あるいは , 2 バイト 文字の一部をなすものて、あるのか , というこ とを示すものて、ある。ふたつの文字列を同時 に ( 交互に ) mbt 。 wc ( ) て、処理しようとする と , 一方の文字列のシフト状態て、別の文字列 を処理してしまうことになる。これは実用上 かなりきつい制限てある。 さらに , 前述したように , theStandardC て、扱う「拡張文字集合」の要素 ( 文字の種類 ) は , locale に依存して切り換えることが可能 て、ある。たとえば , 今は「日本の漢字」 , 次 は , 「韓国のハングル」といったように 0 、、 し , それは , setlocale( ) 関数て、行うのて、ある が , 現状て、は , どのようにして切り換える というところまて、は規定されていない また , 残念ながら , 現在の theStandardC の枠組みの中て、は , このような独立している 複数の文字集合を並列的に処理することはて、 きないと思われる。やるとしたら , 今話題沸 騰の「 ISO 10646 」 ( のように , さまざまな文 字をひとつの文字集合に統合したようなコー ド体系を用いるしかないて、あろう。 また , 同じ文字集合て、もそのエンコーディ ング規則の切り換えに関して , theStandar d C は , 何もいっていないように思われる。 たとえば , JIS, シフト JIS, EUC といったコ ード系の切り換え , あるいは , それらの複数 コード系の並列処理をいったいどうしたらよ 日本語 UN Ⅸ諮問委員会 ( 1984 年に発足 ) プロジェクト ( 1985 年に発足 ) 旧 0 SC22 / WG14 ( 1986 年に発足 ) 情処学会 SC22 / C WG ( 1986 年に発足 ) X3JI 1 国際機能 Ad hoc 委員会 ( 1986 年に開催 ) ソフトウェアベンダーを中心とした日本 C 言語委員 ( 1987 年に発足 ) X/Open UN Ⅸインターナショナル OSF JUS など 44 C MAGAZINE 1 的 2 6 Fig. 10 命名規則 ISXXX - → ISWXXX toxxx ー ' towxxx f{getl put} { い引 char} f{get :put} w{cl 曲 a 「 } [ 日 s] {printfl scanf} [ 日 s] w{printf lscanf} ー , WCS Str
、、 $ ク , あるいは漢字が含まれているソースコ との互換性を考えて , ng の、、 file-io-code' これが , 1 バイト , 2 バイド混在の原稿にして ードは , 「規格厳密合致プログラム」とはいえ をシフト JIS て、はなく JIS に設定している。と いたらさらに頭を悩まさなければならなかっ たて、あろう。 ころが , この前の段落を書き終えたとき , ヒ ず , 移植性がない ) 。 このとき作った修復用のプログラムがまさ また , ソース文字集合に含まれる多バイト ョンな拍子て、 , ファイルが壊れてしまったの て、ある。原稿の途中だけ数十ページ分文字化 に , 前の段落て、述べた「漢字イン , 漢字アウ 文字は , Fig. 5 に示す文脈て、しか使用て、きな トのようなシフトシーケンスがあるような文 い ( ただし , 変数名 , 関数名 , ラベルなどに けしてしまったのだ。 字コード体系を採用している処理系て、は , さ 漢字などの多バイト文字を使うことはて、きな 締め切りもすぎてしまっており , 一時は , 呆然自失の状態て、あったが , 気を取り直し , らに , テキスト処理が複雑になってしまう」 例て、ある。 急遽 , ファイルコードをへキサダンプするツ このように規定されたことにより , the S 参考のために , List 1 にその修復用のプロ ールを作り , 中を覗いてみたら , おかしなこ tandardC て、は , 漢字を含んだ文字列を扱え とが起こっていた。各行の最後の 1 文字の第 グラムを示しておく。これは , pc ー 9801 ノー るようになったが , 漢字を含んだテキストを 2 バイト目だけが , 次の行の最初の 1 文字目の トの上に載せた g032 十 djgcc て、コンパイル 処理するプログラムを C 言語て、記述するに 直前に移動していたのて、ある。そのため , そ し , 実行させた。ただし , これは , 応急処置 は , これだけの仕様て、は不十分なのはいうま れ以降の文字が正しい 2 バイトの組み合わせ なのて、 , 決してよいプログラムて、はない。念 て、もない。なぜなら , もはや , 「 1 文字 = = 1 て、はなく , 隣接している文字の半分ずつのバ バイト」の関係は成立しないため , 従来の AS のため・・ イトが組み合わさって文字化けしてしまって CII コードを処理するように , 1 文字単位のポ ワイ。文字 いたのて、ある。 インタ操作が行えないからて、ある。 これを修復するには , 各行の最初にある 3 また , 漢字イン , 漢字アウトのようなシフ バイトのシフトシーケンス直後の 1 バイト ( 直 トシーケンスがあるような文字コード体系を このような状況を解決するために提案され 前の行の最後の文字の片割れ ) を前の行の最 採用している処理系て、は , さらに , テキスト たのが , ワイド文字て、ある。ワイド文字は , 後の 3 バイトのシフトシーケンスの直前に移 拡張文字集合の要素 ( 文字 ) を表現するのに十 処理が複雑になってしまうて、あろうことは想 動させてやる , というややこしいことをしな 分な大きさの型 wchar t のデータて、ある。 w 像に難くない 余談て、あるが , この原稿は , PC ー 9801 ノー ければいけない char t は , < stddef. h> の中て、 typedef によっ て定義される処理系定義の型て、ある。 トの MS ー DOS 上て、動作するフリーソフト ng 幸い , アルファベットや数字 , 記号の類も すべて 2 バイトコードの文字にしていたの 基本文字集合の要素て、ある 1 バイト文字も ( 日本語 Micro Gnu Emacs) を使って書いて いる。筆者は , 通常 , DOS 上て、も他システム て、 , そう複雑な処理にしなくても済んだが , 含めて , 拡張文字集合の要素は , 均一な大き List 修復用のプログラム List 1 for(i=l;i く max ; i + + ) { int 1 ; char * cp, *strrchr() ; cp = strrchr(buff[i-l], *cp = buffCi]C3); ' yxlb' ・ ' \ X28 ' ・ }x4a' ・ for(j=3;(c=buffCi]Cj + 1]) buffCi)Cj] = 00 4 ・ L.D ^ 0 叮ー 8 0 1 人りな 00 -4 ・一 -0 ^ しー 8 0 イ 1 ワ 0 っ 0 一 4- ^ 0 つんワ 0 りんつりつなワ CO 《 0 00 00 00 の 0 00 っ 0 れ 0 ・ 4- 4 ・・、 4- -4 ・ 4 4 ・ 1 : #include く stdio. h 〉 2 : #include く string. h> 3 : 4 : static char buff [ 500 ] [ 200 ] ; 5 : 6 : main() { int i,J; 7 : 8 : int max ; 9 : int c; 10 : 11 : for(j=0; (c=getchar()) ! = EOF ; j + 十 ) 12 : buffCi]Cj] = 13 : 14 : buffCi]Cj) = 15 : 16 : 17 : 18 : if(c==EOF) break; 20 : 22 : ' yxlb' ) ; for(j=3;(c=buffC0]Cj + (]) い ' 町 buffC0] CjJ ー for(i=0; i く max ; i + + ) { puts(buff[i]) ; break; max 42 C MAGAZINE 1 的 2 6
これて、は標準として不十分に見えるかも しれないが , 思ったよりは有用て、ある。 れを理解するには , ロケールをファイルや ファイルシステムにたとえるとよいだろう。 標準 C がファイルの特質について要求してい ることはほんのわずかて、ある。そうするこ とにより , 多様なコンビュータ上のファイ ルをプログラムからリード , ライトて、きる ようになる。 ファイル名のつけ方についても , 標準 C に はほんの少ししか規定がない。また , イン プリメンテーションが別なファイルサービ スを自由に追加してもよい 大規模な文字集合のサポートに関しても , 同様に詳細な事項と一般的な事項の組み合 わせになっている。 X3J11 は、、マルチバイト 文字″と、、ワイド文字なというふたつの概 念を導入した。大規模な文字集合を表現す る手段としては , このふたつが一般的だ。 マルチバイト文字とは , 1 個あるいは複数 個の文字 ( 訳注 : バイトのことと思われる ) の連続て、大規模な文字集合中の 1 文字 ( 訳 注 : ひとつの要素のこと ) を表現するものて、 ある。ロッキングシフトシーケンスを含む ストリング ( 訳注 : バイト列のこと ) 中にマ ルチバイト文字が存在することもある。し たがって , あるバイトの解釈は , そのバイ トの前の状態に依存する。マルチバイト文 字はシングルバイト経路を使って大規模な 文字集合を送るときに有用て、ある。このよ うなシングルバイト経路にはシリアルコミ ュニケーションラインやディスケット / ハー ドディスク上のテキストファイルなどがあ 一方 , ワイド文字は , サイズが ( 一般的には ) 16 から 32 ビットに固定された整数て、あり , 大規模な文字集合中の一要素のコードを保持 する。ワイド文字がもっとも有用なのは , プログラムて、テキストを操作する場合だ。 両方の形式にはそれぞれの使い道がある。 標準 C て、は , C ソースコード中のコメントお 14 C MAGAZINE 1992 6 よび文字列に基本文字以外の文字を使用し てもよいことになっている。このときの文 字はマルチバイト文字形式て、なければなら 実行時にマルチバイト文字形式とワイド 文字形式とを相互変換し , 変換された文字 を操作するライプラリ関数も標準 C は提供し ている。ロケール機構を使用すれば工ンコ ーディングを ( 一定の制限下て、 ) 切り換える こともてきる。しかし標準 C におけるこのよ うなガイドラインは , どのような大規模文 字集合て、も同じ方法て扱おうとするには最 小限の機能のようだ。 X3J11 は従来から使われていた 1 バイト文 字集合に対して , 特定のエンコーディング を強制していない (ASCII を使って定義して いる Ada の例もあるのて、 , 同じようにしても よかったのだが ) 。これからすれば , 大規模 な文字集合に対して特定のエンコーディン グを強制しなかったのは当然だろう。した がって , 標準 C ては大規模な文字集合のエン コード方法に対していくつかの制限が加え られてはいるが , バリエーションも許可さ れている。 だから一般的な漢字のエンコーディング すべてが使用可能なのだ。 ISO 規格として提 案中の ISO 10646 ュニバーサル文字集合はマ ルチバイトコードとして使えるだろう。ま た , 提案中 ( 訳注 : ある種の業界標準として の提案 ) の Unicode 文字集合はワイド文字コ ードとして使えるだろう。そのエンコード にとって正しくないものを表現しようとし た場合だけ , 問題が発生する。 標準 C て、の国際化アプローチにおけるおも な弱点は経験不足に由来する。それぞれの 部分部分についてはこれまて、の経験が一応 はある。しかし , それらの要素を組み合わ せたとき本当に移植性が向上するのかどう かがまだ証明されていないのだ 私は , すべてをインプリメントすること て、これらの問題を明確にしようと決めた。 programming 聞町咄 その結果として , ちょうど fThe Standar d C Library 』 (Prentice HaIl, 1992 ) とい う本を出版したところだ。 この本には , ロケールと大規模な文字集合 サポートの完全インプリメンテーションが含 まれている。マシンリーダブルなコードも入 手可能なのて、 , それを入手してコンパイルす ればアプリケーションとのリンクも可能だ。 しかもこの形態て、の利用に対してはロイヤ リティが不要てある。私としては , この本 が国際的な市場に対するコーディング実験 の活性化に役立っことを願っている。 化的適応性の良否 まて、。 最終判断がてきない。チャンネルはそのま ューザからのフィードバックがあるまて、は , い。しかしアプリケーションの作者やその ンテーションがよいものて、あるとも思いた いて私は楽観しているし , 私のインプリメ には正しアプローチしているという点につ はまだ早すぎるだろう。て、も標準 C が基本的 しても , それがうまくいくかどうかの判断 はそのほかの真面目なアプリケーションに のこのインプリメンテーションも , あるい 文化的な適応性という面ては , 標準 c も私 うまく合わないかもしれない プが提供している文化固有のサポートとも れない。またほかのべンダや標準化グルー ションからの要求に対しては不十分かもし はなんの制限もないが , 一部のアプリケー を見つけるようになっている。この方法に リがこのファイルをリードして必要な情報 がロケールの変更を要求したら , ライプラ キストエデイタて、指定可能だ。プログラム 式て、は , ほしいだけのロケールを普通のテ ケールファイルの形式を定義した。この形 こともあった。そのひとっとして , 私はロ いろいろと新たに構成しなければならない もちろん , この本を書いている途中には ,
C 概観 いか明確になっていない このように , 現在の the Standard C て、の多 バイト文字処理 ( 日本語処理はその特殊な場 合 ) を行うには , まだまだ間題点が山積して 現在 , ISO C の作業部会 WG14 て、は , the S tandard C に対する「補遺」 (Normatinve Ad dendum) を作成している。この Addendum は , 次にあげる三つのパートに分かれてい ・現仕様の更なる明確化 ( イギリスの提案 ) ・ 3 文字表記法の改善案 ( デンマークの提案 ) ・多バイト文字処理機能拡張提案 ( 日本の提 各提案の詳細な説明は省略するが , この A ddendum は順調に行けば 1993 年中には ISO レ ベルて、正式に登録される予定て、ある。また , この Addendum は , X3J11 て、も正式な提案と して検討されることが合意されており , WG 14 と X3J11 との合同国際会議て、検討されてい る。なお , 多バイト文字処理機能拡張仕様案 ( MuItibyte Support Extensi ons, 略して M SE という ) は , 日本の SC22 / CWG がテクニ カルエデイタになっている ( 本特集 PART 1 参照 ) 。 歴史をひもとけば , ワイド文字の概念の導 入は , 1984 年に発足した日本語 UNIX 諮問委 員会て、の検討にまて、遡ることがて、きる。日本 語 UN Ⅸ諮問委員会は , 当時の AT & T ュニッ クスパシフィック社の諮問を受け , 日本語を 扱える機能を取り込んだ UNIX の検討を目的 として , 東京大学の石田晴久氏を委員長と し , メーカーなどが参加して発足した委員会 Normative AddéR um ノト文字処理機能 拡張提案 ( MSE) 以下に , この MSE を簡単に紹介しよう。 MSE 作成の背景 て、ある。これ以降 , C 言語における多バイト 文字機能をはじめ , UN Ⅸの国際化機能は , この委員会の答申が基盤になっている。この 委員会発足以降 , Fig. 9 に示すようなプロジ ェクト , 委員会が発足し , 国際化機能を議論 し始めた。 このように , さまざまな団体て、似て非なる 仕様が作成されていったが , 国内て、も確固た る実績を持ち , デファクトスタンダードとな るに足る仕様は出現しなかった。 Fig. 9 のい くつかの委員会から , X3J11 に , 多バイト文 字を扱うライプラリ群の提案が何回か行われ たが , 当初は , 実績がない , という理由て、あ まり積極的に検討してもらうことがて、きなか った。 ANSI C の仕様自体が , ' 87 年頃には すて、に固まってきており , 前記のワイド文 字 , および mb 系基本 5 関数を追加することが 精一杯て、あった , というのが実情のようて、あ る。 その後 , 国内外て、乱立している多バイト文 字処理ライプラリを統合し , より完全な形 て、 , ISOC/ANSIC に提案を行うべく , 198 9 年 , 情処学会 SC22 / C WG の下に , 多バイト 文字処理検討サプワーキンググループが設け られた。このサプ WG て、は , 可能なかぎり , 各種関連団体から関係者に参加してもらい , 当時 , 世の中に発表されていた仕様 , あるい は検討中の仕様を網羅し詳細な検討を加え , 全体的にコナセンサスが取れた共通仕様を抽 出した。 1990 年 1 月 , このサプ WG て、作成された多 バイト文字処理提案は , ISO SC22/WG14 に 正式に提出され , ISO C の Addendum 案の一 部として議論されるよになった。 また , 現在て、は , X / Open をはじめ各標準 化関連団体は , 多バイト文字処理ライプラリ に関しては , この ISO SC22 / WG14 の仕様を 採用しており , WG14 の作業と同期を取り , 協力しあいながら仕様案の検討を行ってい る。さらに , ANSI の C 十十委員会 ( X3J16 ) て、も , この多バイト文字処理ライプラリを C 十十における I/O ストリームライプラリとし て取り込むことを検討している。 MSE の内容 特集第 3 の標準』 S C 概観 45 格厳密合致プログラム」て、 , すて、に , MSE の になっているのて、ある。すなわち , 現状の「規 ューザが使用可能な名前空間を侵さないよう じ込められている。 こうすることによって , ァイル < wchar. h > の中に関数原型宣言が閉 MSE のライプラリ群は , ひとつのヘッダフ MSE て、は未解決て、ある。 ストリーム , 複数文字集合の問題も現段階の すべてクリアされているわけて、はない。複数 the Standard C て、の日本語処理上の問題点が しかし , 残念ながら , 前述したさまざまな ード系に対しても十分な考慮が払われてい る。とくに , シフト状態に依存するようなコ 能なように検討が加えられ仕様作成されてい どのような文字コード体系て、あっても実装可 さらに , MSE のライプラリ群は , 処理系が るようになっている。 置き換えるだけて、 , 多バイト文字処理カイき 対して , 原則的には , 単純にライプラリ名を ト文字べースのテキスト処理のプログラムに を形成している。したがって , 従来の 1 バイ ヾイト文字べースのライプラリとのアナロジ また , これらのライプラリ群は , 既存の 1 な規定を設けることだけが許されている。 efined behavior) となってしまう部分に新た um て、は , 現仕様の中て、「未定義の動作」 (und いい換えれば , Addend なければならない 密合致プログラム」がそのまま受け付けられ 仕様を実装した処理系て、も , 既存の「規格厳 ることは許されない。つまり , Addendum の 仕様」て、あるから , 既存の仕様に変更を加え ただし , Addendum は , あくまて、も「追加 の機能をサポートするのて、ある。 が等しいワイド文字に変換して処理するため イト文字のままて、はなく , 各文字のバイト数 これは , あくまて、も , 文字列データを多バ 加する。 て、処理を行うための完全なライプラリ群を追 に修正を加えることなく , ワイド文字べース MSE て、は , 現状の the Standard C の仕様
TabIe 1 に LASER SHOT におけるテキス TabIe 1 LIPS コマンドー覧 ( テキストモード ) つづき トモードのコマンドの一覧を掲げる。 コマンドの内容 さて次に このような命令をどのように プロボーショナルスペーシング動作許可 プリンタに送出するかて、あるが , これはい H Ⅶ自動変更禁止 H Ⅶ自動変更許可 たって簡単て、ある。すなわち , fprintf() 関 プロポーショナルオフセット設定 印字位置オフセット設定 数を使用することにより命令を送ることが 3. 位置単位モード設定制御 て、きる。たとえば , テキストモード開始命 令は以下のように記述すればよい サイズ単位モード設定 行桁モード設定 fprintf (stdprn, "%c%%@" , 0x1B) ; 4. 印字位置移動制御 もっとも UNIX の場合は ,stdprn は定義さ れていないのて、 , 筆者はプリンタが接続さ 垂直水平絶対位置移動 垂直絶対位置移動 れているデバイスファイルを List 1 ( 129 頁参 水平絶対位置移動 上方向位置移動 照 ) のような形て、 open し , そのファイルポイ 下方向位置移動 左方向位置移動 ンタを stdprn という外部変数に代入するとい 右方向位置移動 う方法をとっている。 位置記憶 / 移動 5. タブ制御 明細書印刷プログラム 水平タブ設定 水平タブ 垂直タブ設定 LASER SHOT の表現力を試す意味を含 垂直タブ 垂直タブ自動復帰許可 めて , 今回はより実際的 , 実用的な印字プ 垂直タブ自動復帰禁止 タブ解除 ログラムを作成してみた。具体的には , 医 文字セット制御 療機関て、使用されている診療報酬明細書用 紙を印字するプログラムを作成してみた ( 付 1 . 文字セット呼び出し 録ディスク収録 Iips4. tst ) 。この用紙の作成 シフトイン シフトアウト については印刷会社に委ねるのが一般的て、 LS2 LS 3 あり , その価格もかなり高価と聞いている。 SS2 そこて、 LASER SHOT て、印字することがて、 SS3 LS 1 R きれば , それだけて、コストダウンが図れる。 LS2R LS3R まず Fig. 2 をご覧いただきたい。左が印刷 2. ペア指定 業者が作成した用紙て、 , 右が本プログラム て、作成した用紙て、ある。文字の大きさなど ペア指定 に若干の相違があるものの , ほとんど違い 3. 文字セット属性選択 がわからないほどの用紙を作成することが GO グラフィックセット指示 ( 1 バイト ) G 1 グラフィックセット指示 ( 1 バイト ) 可能て、ある。 G2 グラフィックセット指示 ( 1 バイト ) G3 グラフィックセット指示 ( 1 バイト ) もっともこのプログラムについては , さ GO グラフィックセット指示 ( 2 バイト ) まざまな機種を想定して , コマンドは LIPS GI グラフィックセット指示 ( 2 バイト ) G2 グラフィックセット指示 ( 2 バイト ) Ⅱまて、のものを使用しているのて、 , LIPS Ⅲ G3 グラフィックセット指示 ( 2 バイト ) 文字ピッチ選択 のコマンドを使用すればさらに近いものを 文字サイズ選択 文字スタイル選択 ( イタリック ) 印字することがて、きる。 文字スタイル選択 ( アップライト ) ストロークウエウト選択 ( ボールド ) 本プログラム ( Iips4. txt ) て、は年月 , 医療 ストロークウエウト選択 ( ライト ) ストロークウエウト選択 ( ミティアム ) 機関名 , 枚数などの入力をプログラムに組 書体選択 み込んだが , これをキーポード入力に切り 124 C MAGAZIN E 1992 6 コマンド 3 3 8 つなっ 4 C 0 O ( しつムっ 0 ( し O ( , * 十 $ $ $ cn E 3 E E 2 っ 0 っ 4 1 つっム > ・
データセグメントのサイズ 64K バイト と設定されるため , near ヒープ 64K バイトー ( 静的データ十スタック ) となります。 Fig. 1 に TurboC 2.0 / C 十十 1 . 0 のスモ ールモデルの一般的なメモリ構造を示しま す。 near ヒープ領域とスタック領域がお互 いに反対側からまん中に向かって伸びるよ うな仕様になっているため , デフォルトの heaplen = 0 の状態て、は near ヒープ領域とス タック領域が最大限に効率よく取られるよ うになっています。そのため , スタックオ ーパフローが発生することはほとんどない と思います。ほとんどの人は , 上記の 2 変数 を設定していないと思われますから , スタ ックサイズを設定しなければ最大限に確保 されるという仕様は初心者にとってやさし い仕様となっています。 MS-C 5.1 / 6.0 の場合 MS-C 5.1 / 6.0 て、はスタック領域の大きさ はリンク時に決定されます。 MS-LINK(L INK. EXE) のスイッチ </stack (/st) がスタ ックサイズの指定て、 , デフォルト (/stack を 指定しない場合 ) て、は , 2K バイトとなりま す。このため , auto 変数の配列がいくっか あると , 簡単にスタックがオーパフローし てしまう可能性があります。たとえば , char buf [BUFSIZ] ; などの auto 変数の配列が四つあると , 2K バ イトになります。また ,/cparmaxalloc(/cp) は near ヒープ領域の大きさに関係するスイ ッチて、 , デフォルトて、は FFFFh (FFFFhx 10h バイト IM バイト ) となるため , デー タセグメントのサイズは最大限の 64K バイト に設定されます。そのため , 67 72 9 28 List プログラムのサイズを確認するテストプログラム (listl . c ) 1 : #include く stddef. h> 2 : #include く process. h 〉 int main( VOid ) static char memmap[] = "memmap. exe"; / * メモリ・マッフ。を調べるユーティリティ return( spawnlp( P WAIT, memmap, memmap. 8 : 7 : 6 : 4 : 3 : Copyright C Microsoft Corp 1985 ー 1990. AII rights reserved. Microsoft R EXE Fi le Header Uti 1 ity Version 2.01 E:} 〉 exehdr 1 istl Fig. 5 List 1 の実行例 ( MS - C 6.0 ) . EXE size (bytes) Magic number: Bytes on last page: Pages in file: Relocations: Paragraphs in header: Extra paragraphs needed : Extra paragraphs wanted : lnitial stack location: Word checksum : Entry Relocation table address : 001e Memory needed : E:#>list1 1831 5a4d 0031 000d 0005 0020 0081 ffff 0164 : 0800 572b 0000 : 002C 8K システム フ。ロク・ラム フ。ロク・ラム 環境変数 フ。ロク・ラム 環境変数 フ。ロク・ラム フ。ロク・ラム 環境変数 フ。ロク・ラム 空き PSP サイス・親 PID フ。ロセス種別 ← MAXALLOC ←スタックサイズ 800h = 2K ノヾイト ① MCB ー十一十一 4164 Z 3973 M 3947 M 2817 25dc M 25ab 24cf 24a3 M 249d M 2349 M 1186 M 8 234a 249e 2818 24d0 24d0 25dd 2818 3974 3974 0 11C2 153 5 2b db 30 23a 112f 2b 7f0 5e9b 24d0 24d0 24d0 2818 Trap vectors 0 22 6 21 23 24 2e フ。ロセス名 COMMAND. COM ? ) COMMAN D. COM ? ) E:YLIST2. EXE E:}LIST2. EXE ←サイズ 1 12fOh バイト② A : YUTLYmemmap. exe A : YUTL*memmap. exe E:*>exehdr / x : 1 listl ← nea 「ヒープ領域のサイズを 0 バイトに設定する③ Microsoft (R EXE File Header Utility Version 2.01 Copyright (C Microsoft Corp 1985 ー 1990. A11 rights reserved. EXEHDR: error U1106 : minimum allocation greater than maximum; correcting maximum . EXE s i ze (bytes ) hagic number: Bytes on last page: Pages in file: Relocations: Paragraphs in header: Extra paragraphs needed: Extra paragraphs wanted : lnitial stack location: Word checksum : Entry point: Relocation table address : 001e Memory needed : 8K 0000 : 002C 572b 0164 : 0800 0081 0081 0020 0005 000d 0031 5a4d 1831 ← MAXALLOC を最小に変更 ←スタックサイズ 800h = 2K バイト 76 near ヒープ C MAGAZINE 1992 6