LANGUAGE COMPUTER LANGUAGE 発音の類による文字の ALGORITHMS FNE-T1k 優「 A 第 02 æPÆRATION 刀レゴリズム : Metaphone 1 袵ル & Hanging on the Metaphone Lawrence Philips/ 岩谷宏訳 (COMPUTER LANGUAGE/Dec. 1990 ) 法とては SOUNDEX か有名だが , もっとよい方法かある 音声的なテキスト検索 提携記事 List 1 ENC_METAP. C 1 : / * ENC_METAP. C : 入力文字列 name を読んで , それに対応する , Metaphone アルゴリズム 2 : による音素文字列を配列 metap に収納し , metap を返す。 3 : 4 : 工ラーならば NU ししを返す。 5 : 6 : from COMPUTER し ANGUAGE, Dec. 1990 7 : "Hanging on the Metaphone" bY し awrence Phi lips (written in Pick BASIC) 8 : 9 : ported to C by H. lwatani, Jan. 1991 12 : # i nc I ude く std i 0. h > 13 : #include く string. h> 14 : #include く ctype. h> 15 : 16 : #define TRUE 1 17 : #define FA し SE 0 18 : #define MATCH 0 19 : #define STR_TOP 1 20 : 21 : #define VOWELS ” A OU ” 22 : #define FRONT_VOWE し S "EIY ” 23 : #define VÅR_SOUND ” CSPTG ” 24 : #define NO_TRNSFRM "FJ し MNR ” 25 : 26 : static int pos; 28 : / * 29 : * 文字列がすべて ASC Ⅱアルファベット文字で成り立っているか 30 : 31 : static int is all_alpha( char *string ) 32 : { 33 : while( *string ) { 34 : if( ! isalpha( *string + + ) ) 35 : return FALSE; 36 : return TRUE; 38 : } 39 : 40 : / * 41 : * 語の最初の文字に対する特例措置 42 : 43 : static char *adjust_initial_letters( char *string ) 44 : { 45 : char first, second; 46 : 「音的」な 検索の要求 顧客は不満なようて、す。あなたが作った データベースは , 完璧な仕上がりて、 , 企業 名て、も数字て、も検索がて、きます ( 名前や番号 を覚えてさえいればね ) 。なのに彼らは , 「探 している会社が見つからない」というのて、 す。つまり , 社名の正確な綴りを忘れるこ とが多いらしいのてす。だから彼らはあな に , 「音的に」それらしい名前て、検索のて、 きるプログラムを作ってくれと要求します。 この問題を解決するための , もっともよ く知られているアルゴリズムが SOUNDEX て、す。て、も , 私はヘンだと思います。 SOUN DEX は , 英語の発音の基本規則を無視し て , どんな状況ても g 〃と当クは等しいとし , z ヾ k 〃をひとまと めにします。 ( SOUNDEX ては ) 一部の ( 文字間の ) わか りきった同等性に対応するために , 基本ア ルゴリズムにクラッジがいくつも加えられ ています ( そのアルゴリズムの基本論理とは 無関係な if ・・ then 文を加えるなど ) 。て、も クラッジはしよせんクラッジて、す。とにか く , 英語はこの方面て、は厄介者てす。あの / * ' h ' を加えると音が変る字 , この C 版では不使用 * / / * そのままを音素文字としても使う * / 20 C MAGAZINE 1991 4
なりこれに依存した記述が多いのて、 , XC に確保されるのが一般的て、 , XC 用の alloca ( ) ん。 GCC て、はこの関数の機能は , builtin make て、はいくつかの生成規則を明示しておもネットなどて、入手することがて、きますが , a Ⅱ。 ca ( ) を呼び出すことて、実現て、きます。 XC のオリジナルライプラリには存在しませ この関数は本来 C には備わっていない「組み く必要があると思います。 次に , マクロ X68000 を定義してコンノヾイ ルすれば避けられるように手を入れてあり ますが , XC の標準ライプラリにない関数が あります。 List 1 は GNU ソフトを移植する 場合に常套的に用いられるマクロ定義て、す。 これと同様なマクロには USG を定義すると 有効になるソースが多いのて、すが , これを 定義するとほかの部分て、問題が起きたりし ますのて、 , List 1 のようなマクロを常備し ておくと便利て、す。 ほかに問題となるのは , alloca ( ) 関数て、 す。これはスコープが関数の内部だけの malloc() のような関数て、 , 指定されたサイ ズのメモリを確保してその領域へのポイン タを返します。 malloc( ) と異なるのは , そ の領域はその関数に制御が存在する間だけ 有効て、 , free ( ) を呼び出して明示的に解放す る必要がない点て、す。 List 2 をご覧くださ これは , size バイトのメモリを alloca ( ) て、 確保する例て、す。 a11 。 ca ( ) が返したメモリ領 域は a110C test ( ) 内て、あれば有効なのて、 , そ の領域をポインタとして関数を呼び出すこ とが可能となり , また明示的な解放の必要 がないのて、 , GNU ソフトウェアて、は好んて、 用いられています。この領域はスタック上 注 4 以前にこの連載て、紹介した可変長の自動 変数の配列は , これの応用て、あるのは推測 て、きるて、しよう。 LiSt 1 : / * This Macro is very usefull on X68000 * / 2 : #define index strchr 3 : #define rindex strrchr 4 : #define bcmp(a,b,c) memcmp ((b)' (a)' (c)) 5 : #define bcopy(a,b,c) memcpy ((b)' (a)' (c)) 6 : #define bzero(a,b) memset ((a), 0 , (b)) List 1 : a 1 1 oc test ( i nt s i z e) 3 : 4 : 5 : 7 : 9 : 10 : * このソースを builtin_alloca #define alloca 12 : を追加してコンパイルした結果 20 : 24 : 28 : 29 : ? 5 : 30 : 33 : 34 : ? 6 : 35 : 36 : 37 : 38 : i nt i ; alloca (size); char * buf 0 ; i く S i ze : i 十十 ) for ( i buf[i] call (buf) : cd 0 ー 0 0 , ー 0 一 11 , 0 ー 0 一 4 , ー 0 0 れ 0 11 , # # 0 , 8 ・ロ # ワ 0 0 1 ーー 0 十》 ^ 0 れ 0 0 ー 0 E 十レ Q) O ・ー・ 0 0 0 0 E 1 ー 0 cd * 引数を得て * アラインメントをとる * スタックから確保 * そのポインタを使う 注 5 XC のスタックチェックを指定して実行し た場合 , 実際にオーバーフローしたときに 工ントリするルーチンは動作しません。な ぜかオーバーフローしたはずのスタックを 再度使っています。 move. 1 a0, -(sp) jsr -call un 1 k a 6 rts 140 C MAGAZINE 1991 4
tlsubwin. C List 3 MS-C MS ー C てコンパイルする場合には , 従来と 同様にコンパイルスイッチを設定するとと もに , MS ー C コンパイラのディレクトリ (MSC) 下の INCLUDE ディレクトリの中に , config. h として以下のファイル <MS-C 用 config. h > を入れておく必要がある。 CL /AL /Od /W2 /Zi /J /c 関数 . c ( ラージメモリモード /CodeView を使 用 / 警告レベルは 2/char を unsigned char にする / リンクは行わずコンパイ ルのみ行う ) く MS-C 用 config. h> #define MSC #ifndef MSDOS #define MSDOS 3 : 4 : # i nc 1 ude "config. h" 5 : 6 : #define EXTERN extern 7 : 8 : 9 : #include く coniO. h> 10 : #include "pldwn. h" 11 : #include ”ⅵ ndow. ド 13 : # ifdef PROTOTYPE 14 : #include "cboxprot. h ” 15 : #endif 17 : / * ウインドウ内の特定の属性の追加 19 : tIsubwin(MWINDOW *pw, 20 : unsigned xl, unsigned yl, 22 : unsigned x2, uns igned Y2) 23 : 24 : { 25 : unsigned ylen; 26 : unsigned xlen; 27 : unsigned ystart; 28 : unsigned xstart; 29 : 30 : ー yl + 1 : ylen : x2 ー xl + 1 : Xlen 32 : ystart = yl 33 : xstart = XI subwin(pw, ylen, xlen,ystart, xstart) : 34 : return( の : 35 : 36 : } Copyright 1990 E. TOY0kuni Number T し * / CM910402 #endif #ifndef PROTOTYPE #define PROTOTYPE #endif tlwfresh. c List 4 Copyright 1990 E. TOY0kuni Mod i f i ed 91.01. 18 4 : 5 : # i nc 1 ud e ” config. h ” 6 : 7 : #define EXTERN extern 8 : 9 : 10 : #include く coniO. h> 11 : #include ” pldwn. h ” 12 : #include ” window. h ” 14 : #ifdef PROTOTYPE 15 : # i nc I ud e "cboxprot. h" 16 : #end i f / * ウインドウ内の特定の属性の追加 20 : tIwfresh(MWINDOW *pw, char *title) 22 : { 23 : unsigned xl : 24 : unsigned yl; 25 : uns igned char attr; 26 : ー pw->xl = pw->yl 28 : attr = pw->kattrib ・ wrefresh (pw) : 29 : 30 : printv(title,attr,xl + 2,Y1, の : return ( 0 ) : 32 : } Number T し CM910403 参考文献 WiIIiam James Hunt *The C TooIbox" Addison-Wesley, 1989 [ 追記 ] 前回 ( ' 90 年 3 月号 ) の Tu 市 0 C への移 植記事において , 定数 REVERSE, B 凵 NK のニ重定義問題を # ifdef で処理 しましたが , 実際には筆者の定義した 値と conio. h で定義している値とが必ず しも一致しなかったので , 今回から p 旧 wn. h で定義している REVERSE と BLINK は REVERSEE と BLINKK に改め ることにしました。前回のプログラム についても , 同様に訂正してください。 98 C MAGAZINE 1991 4
箱 語具 の ンパイルスイッチを以下のように設定する とともに , Turbo C コンパイラのディレク トリ下の INCLUDE ディレクトリの中に config. h として以下のファイル <Turbo C 用 config. h > を入れておく必要がある。また統 合環境てコンパイルするのてはなく , TCC を使用する。 tcc -v -K -J -w -ml -c ( デバッガを使用 /char を unsignedchar にす る / 漢字を使用する / 警告あり / ラージメモリ モード / リンクは行わずコンパイルのみ行う ) く Turbo C 用 config. h> #define TURBOC #ifndef MSDOS #define MSDOS LiSt 1 158 : 159 : 160 : 161 : 162 : 163 : } } wh i 1 e ( i i CURON; exit(0); = ESCAPE ) : Fig. 6 f ・ 9 を押す (TEST. EXE) ′℃ T 能 E : ヨ洋や プリンタの準かは三 = しけれに河かキーを押して下さい #endif #ifndef PROTOTYPE #define PROTOTYPE #endif chgfnc70. c List 2 List 2 strcpy(kugiri, token[i] = strt0k(moji2, kugiri) : while( token[i] ! = NUL し ) { token [ + + i ] : strt0k(NULL, kugiri) : n 1 for(i = 0 ;i く NUM 三 i + + ) { strcpy(fnc[i], for ( i = 0 : i く n : i + + ) { strcpy(fnc[i], token[i]) : for ( i = 0 : i く 10 : i + + ) { if( i く 5 ) { = 8 * i -4 LO ^ 0 0 ー 8 0 》 0 11 っ 0 っ 0 -4- ′ 0 e.D ー 8 0 1 よっ 0 っ 0 -4 ・ -0 0 ー 8 0 1 よっ 0 っ 0 -4 ′ 0 っ 0 っ 0 っ CO っ 0 -4 ・ -4 : 4 : 4 : 4 : 4 -4 ・ -4 ・ -4 ・ -4 ・ - -0 ′ 0 戸 0 ′ 0 -0 ′ 0 戸 0 - -0 戸 0 L.n CD ^ 0 6 ^ 0 Serial CM9104 * Copyright 1991 E. Toyokuni Version 01 2 : 3 : 4 : 5 : 6 : # i ncl ude ” config. h" 7 : 8 : #define EXTERN extern 9 : 10 : # i ncl ude く stdio. h> 11 : # i ncl ude く string. h> 12 : # i ncl ude "pldwm h ” 13 : 14 : #ifdef PROTOTYPE "cboxprot. h" 15 : #include 16 : #endif 17 : 18 : chgfnc70(moji, color, ura) 19 : Char *moji : 20 : Char color; int ura : 21 : 22 : { 23 : #define NUM 10 24 : char fnc[NUM] [ 8 ] : 25 : i nt i = 0 , n : 26 : i nt X : 27 : char cxC10]; 28 : char *t0ken[40] : 29 : char kugiri[10]; 30 : char moji2 [ 120 ] : 32 : BOTTOMOFF : strcpy(moji2, moji) : 33 : X else{ = 8*i + 1 X n ニ 7-strIen(fnc[i]); if (n くの { mid(cx,fnc[i],I,7); strcpy(fnc[i],cx); strncat(fnc [i], printv(fnc[i],color ー REVERSEEINONSEC, x, 24 , ura) : return( の : 応用 C 言語 97
ワンポイント プログラミング 講座 List 1 1 List 94 : 96 : 97 : 98 : 99 : 100 : 101 : 102 : 103 : 104 : 105 : 106 : 107 : 108 : 109 : 110 : 111 : 112 : 114 : 116 : 1 18 : 1 19 : 120 : 121 122 : 123 : / * RK Search C-MAGA ・ 90. Aug. 124 : #define し ARGE PRIME 554383 し 125 : #define NUMBEä OF_CHAR 256 int rk-search (éhar *pattern, char *text, int text_len) 126 : 128 : long dm = 1 , hl = 0. h2 = = LARGE_PRIME: 129 : i nt i, n, d = NUMBER_OF_CHAR : 130 : strlen (pattern) : 131 : m 132 : n = text_len : 133 : for (i 134 : 135 : dm 136 : 137 : for (i 0 : i く心 i + + ) { 138 : hl hl * d 十 long pattern[i]) % q; 139 : h2 = h2 * d 十 long text[i]) % q; 140 : 141 : while (n 142 : 143 : 144 : 145 : 146 : return(i く = n ー田 ? i 147 : 148 : } 1 : 2 : / * DEVMAP. C : デバイスドライバの情報表示 ラージモデルでコンパイルしてください。 〉 C し /A し DEVMAP. C 5 : 6 : #include く stdio. h> 7 : #include く stdlib. h> 8 : #include く dos. h 〉 9 : # inc lude く jctype. h> 10 : #include く string. h> 11 : / * #define DEBUG * / / * デバッグ情報表示 * / 13 : / * 関数プロトタイプ * / 14 : void dump(char *S, int n) : 15 : char *dev_stat char *header) : 16 : i nt rk search char *pattern, char *text, int text len) : 17 : / * グロバル変数 * / 18 : Char *nul = ” NU し 19 : 20 : 21 : / * DEVMAP MAIN FUNCTION 22 : VOid main(void) 23 : { 24 : union REGS regs; 25 : struct SREGS sregs; 26 : Char *first_mem, *dev; int 28 : 29 : ニ 0X5200 : regs. X. ax 30 : intdosx (®s, ®s, &sregs) : 32 : FP_SEG fi rst_mem sregs. es: 33 : FP_OFF first 田 e 田 regs. X. bx; rk searcfi(nul, first-mem, 256 ) : 34 : if (i ~ の { 35 : printf("Sorry, bat ー cannot find nul device. 36 : 37 : return; 38 : 39 : dev = first_mem 十 i ー 0x0AL : 40 : #ifdef DEBUG printf ( " * * * dev ice header address dump (dev, 26 ) : 42 : 43 : #endif printfÜAddress Stra tr Attr N000 \ 0 " : 44 : while (long) (dev = dev_stat(dev) ) ! ニ 45 : 46 : 48 : 49 : / * デバイス情報の表示 50 : char *dev stat(char *header) 51 : 52 : int *wd, stra, intr, attr; 53 : i nt i , un i t, d rv : 54 : Char *s: 55 : (int * ) (header + 4 し ) : / * 先頭から 4 パイトは次のデパイス * / 56 : wd / * へのリンク情報 / * デパイスの属性 58 : *wd 十十 : attr / * ストラテジェントリポイント 59 : *wd 十十 : Stra / , 掣り込み = ントリポイント 60 : intr - *Wd 十十 ; (char * ) (header + 10L ) : / * パイス名またはユニット数 S printf("X04X:X04X % 04X % 04X % 04X ” 62 : if ( at を 0 & 0 , 8 圓 3 ' { FP_0FP(header) , stra, intr, attr) : 63 : / * キャラクタデバイスの場合 for ( i 65 : putchar ( * s 十 + ) : putchar( ・・ ) : 68 : 69 : else { 70 : unit * S 十十 : if ((((int)*s) & 0xff) drv else { 75 : 76 : drv 0 : i く unit; i 十 + ) { for ( i printf("Xc: drv 十十 ) : 79 : putchar( ・ Yn ・ ) : 82 : #ifdef DEBUG dump(), 8 ) : 83 : 84 : #endif return ( (char * ) (*(long * ) header) ) : 89 : / * メモリ報の表示 90 : void dump char *S, int n) 92 : i nt i. char bufti6] : 93 : 十・ 0 、 / CD .0 , く十》 0. 0 X 01 ー 1 ヂー 0 if (j ! = の { for ( i bufii\' printf(" printf( ” for (k = 0 : k く 16 : k 、 +B){putchar(buf[k]): else putchar printf( ” Yn ” ): i く 16 : i + + ) { h2 , d + ?long )text[iimf)l]x*qdm) % = 0X9 の { ワンポイントプログラミング講座 121
順列の生成 LANGUAGE 提携き事 if( n ! = 0 ) 1 ー & 11 平 物ー 順列 , 組み合わせに関する基礎知識は欠かせません。 シミュレーションをプログラミングする場合 , 確率や ① r 第題題一①羆 Ge 羆① r 題一①羆 Joe CeIk0 / 岩谷宏訳 E (COMPUTER LANGUAGE/Dec. 1990 ) LANGIJAG ALGOIITHM# ′ン プログラミングの問題に入る前に , 話の 順序として , 数学の復習を少ししましよう。 、、 n ! ″と書く階乗という関数はご存知てすよ ね。その定義は「 1 から n まて、のすべての数の 1 という約束 積」て、す。ただし特別に , 0 ! があります。これはたいてい , プログラミ ングの参考書の再帰関数を学ぶ最初に登場 しますから , ほとんどの人が知っています。 それはふつう , 以下のように書きます。 int factorial( int n ) return 1 ; else return n * factorial( n これは , 計算機資源のおそるべき浪費て、 す。しかし , 実用価値がありそうなことを する再帰関数としては , もっとも短いもの の一つなのて、 , 本には頻繁に登場します。 単純に for ループを使えば , 時間もメモリ も少なくてすみます。 int factorial( int n ) int i, fact : 26 C MAGAZINE 1991 4 fact return fact : fact fact fO 「 ( i 十十 i ( 訳注 : 上記 2 ルーチンとも , n が負数だった . 場合の対策を施していない フロー時の対策も省略されている。なお , 原文て、はリストは Pascal て、書かれている ) このバージョンて、も , 問題を免れません。 階乗関数は急速に肥大して , 計算機の整数 の大きさの限界という壁に激突してしまい ます。 その対策の一つとして , スターリングの 公式は , n ! の値の良質な近似を作ってくれる のて、 , n の値が大きいときには便利て、す。そ の公式は , #include <math. h> #define pi 3.141592653 #define e 2 .718281828 long stirling( int n ) return(long)( sqrt( 2 * pi * n ) の並び ( べ ) 方 階乗が大いに役に立つ場合の一つが , 順 列 / 組み合わせの計算てす。あなたが漫画本 を n 冊もっていて , その中から k 冊を選んて、 友達に売りたいとしましよう。この場合の , サイズが k という部分集合は , 何通りあるて、 しようか ? この数値のことを n 個から k 個 を取る組み合わせと呼びます。 そういう部分集合が得られたとして , そ れて、は , それらのおのおのを並べる並べ方 は , 全部て、何通りあるて、しようか ? この , 並べ方の数のことを n 個から k 個を取る順列 と呼びます。 順列 / 組み合わせの用語はよく混同しがち て、す。体育館のロッカーの組み合わせ ( 物理 的な組み合わさり状態 ) には順序があります が , 数学用語の組み合わせには ( 順序という 概念が ) ありません。「体育館の 36 個のロッ カーから 3 個とる順列を求めよ」という数学 の問題に出会っても , びつくりしないよう 少し考えると , n 個の物 ( 文字 , 数字など ) * pow( n/e, (double)n ) ) :
= レポート 最新ロ 新マクロ構文の例 ( BLOCK ー S 印 FT. CB ) Li st て、は , Brief から MAKE を呼ぶにはどうす るのか。 「 . MAK ファイルを MAKE, NMAKE な どて、実行する」と SETUP しておけば MAKE によって . EXE ファイルを Brief の中から作 成て、きるのて、ある。 このように各段階を支配しているのはフ ァイルとその拡張子て、ある。これは使いよ うによっては , 統合環境とほとんど同じ機 能を使用て、きることを意味している。 ージョンアップの実際 以上が前バージョンから受け継がれてい る Brief の概要て、ある。ここて、は今回のバー ジョンアップに伴った改良点と使用上の注 意点について述べていこう。 C ライクなマクロ言語とマクロテパッガ 則バージョン , 2.1 て、は , マクロは各構文 が全体をカッコて、くくった LISP ライクなマ クロだったが , 今度の Ver. 3 て、は C 言語のよ うなマクロ構文が追加された。処理構文は まさに C 言語そのものて、 , 演算子も基本的に 同じものが使える。ばっと見ただけなら見 なれない関数が並ぶ普通の C のソースにしか 見えないだろう。内部て使う変数の宣言も 簡単だ。 残念ながら今回試用したのが版なのて、 , マクロデバッガはディスクに収められてい なかった。マクロデバッガ自身をマクロて、 実現しているようだ。 口を動かしながら内部の状態を見ることが 一般論としてはエデイタのマクロは実際 てきるようだ。これは製品版に期待したい に動作させてみないと最終的にどんな挙動 そのほかの細かい変更点て、 , 今回のバー をするかわからないものだ。 C て、よくやる printf ジョンアップによってもっとも使い勝手がよ デバッグのようなことがて、きることはほと くなったのは , ウインドウのズームが んどないし ( なにしろ工デイタにおいて DOS 十図一発てて、きるようになったことだろう。 のコンソールにあたるのは編集領域だった これによって参照用に小さいウインドウを りする ) , 単純に思えるカーソル移動にして 作っても変更時に編集しやすいようにズー も全角半角の扱いに苦しめられたりするこ ムてきる。 とも多い また , 各部のメッセージ , ドキュメント 今回リリースされた BriefVer. 3 て、はマク #define RIGHT 1 #define LEFT 2 VOid slide-in(void); slide out(void); VO i d paren(void) : int void block_shift(int direction) block-mark(void) : int save position ( ) ; if (block-mark ( ) ) { switch (direction){ case RIGHT: s 1 i de_ i n ( ) : case LEFT: sl ide-out ( ) : raise_anchor ( ) : restore-position ( ) : 定数の置き換え カーソル位置を保存 プロックがマークできたか ダイアログボックスを通じて * / 右シフト 左シフト マークを消す カーソル位置を元に戻す int block-mark (void) / * まず { を探す . ! は論理否定 * / if (!search-back ( " \ \ { " ) ) { message ( " { が見つかりません " ) ; return 0 ; / * マークできず down ( ) : / * カーソルは { にいる drop anchor ( 3 ) : / * マークは次の行から up 0 : / * { の位置へ if (paren ( ) ) { / * 相手の } へ進む / * } が有れば / * 上の行までがプロック return 1 : }else{ / * マーク O K message ( " } が見つかりません " raise_anchor ( ) ; return 0 : が日本語化された。とくにダイアログマネ ージャに関するドキュメントの日本語化は 非常に助かる。 バージョンアップに伴う注意点 環境設定する場合 , Brief て、はインストー ラて環境変数領域として宣言する量を設定 するのだが , これが最大 1008 バイトまて、と なっている。この 1008 バイトというサイズ は , 東芝などの DOS< はちょうどいい大き 133 最新開発環境レポート
シャープ X グループ lnformation from Compiler Makers List 1 (l) ma ー n. C static int a = 10 : main() sub(): Sub. C extern int a; sub() printf("a=XdYn" 0 0 して扱われますのて、 , auto を指定 います。省略した場合は , auto と きるのは , register のみに限られて の記憶クラス指定發として指定て、 定することはて、きません。仮引数 記憶クラス指定發として auto を指 関数の仮引数リストの宣言て、は , 宣言につして 関数の仮引数リストの 変数として扱われます。 指定發を省略した変数は , extern なお , 外部レベルて、記憶クラス のように変史してください うにします。たとえば , List 1 ( 2 ) 数は static て、変数宣言を行わないよ って , て、参照したい変 ースファイル内だけて、す。したが 変数の通用範囲は , 宣言を含むソ て参照することはて、きせん ostatic プログラムから externfi 言によっ 外部宣言した static 変数を , 別の 外部変数の参照につして extern 宣言による するときの参考にしてください 介しますのて、 , プログラムを作成 ラミングするときの注意事項を紹 て、今回は , XC ver2.0 上て、プログ ージョンアップされました。そこ C compiler PRO-68K(XC) がバ C MAGAZINE 1991 4 したい場合 , 記憶クラス指定 f ・は 154 ma ー n. C int a=10; nain() sub(); sub. C extern int a; sub() printf("a=XdYn". a) : ープサイズを指定するには , コン パイル時 , プログラム実行時 , プ ログラム中の 3 種類が選択可能て、 す。 コンパイル時に指定する場合 は , "/Gh" スイッチをつけること により実行時のヒープサイズを 指定することがて、きます。指定 て、きるヒープサイズの , 最小値 は 8K バイト , 最大値は利用て、き るメモリのサイズによって変化 します。 A> cc /Gh100k m 訓 0C1. c ・プログラム実行時一一一一一一 - プログラム実行時に指定する 場合には , 実行時にソ HEAP : 〃ス イッチをつけてヒープサイズを 拡大することがて、きます。 List 3 Char 6 : main() 4 : #define B_SIZE 1024 * 64 2 : #include く stdlib. h 〉 . #include く stdio. h> C compiler PRO-68K ver 2.0 A> mallocl /HEAP:100k プログラム中て、指定する場合 には , C のメインプログラムの中 て、変数の宣言て、 sbrk 関数て、メモ リサイズを指定します。詳細は List 4 を参照してください。これ により , プログラムの実行中に ヒープサイズを拡大することが てきます。 List 2 void fnc(auto int x) void fnc(int x) ェラーヘンダファイレ 省略します。 List 2 を参照してくだ 0 error. h" を、、 errno. h" に RE ァイルをコンパイルするときは , ングや , 他の処理系の C のソースフ て , ANSI C に準拠したプログラミ 換性を保っためて、す。したがっ 作成された C のソースファイルとの ています。これは , XCverI. 01 て、 が , XC ver2.0 て、は、、 error. h" とし 名は , 、、 errno. h 〃となっています ANSI C のエラーヘッダファイル について 0 NAME してください 大することが必要となります。ヒ するためには , ヒープサイズを拡 64K バイト以 E のメモリを確保 モリを確保することがて、きません。 ると , NULL が返されてしまいメ ト以止のエリアを確保しようとす ムのように malloc 関数て、 64K バイ すのて、 ,List 3 のサンプルプログラ 値は , 64K バイトと設定されていま ます。ヒープサイズのデフォルト ヒープサイズの大きさまて、となり きる最大メモリサイズは , 合計て mall 。 c 関数て、確保することがて メモリ確保 m 訓 oc 関数による 3 : 5 : 8 : 9 : 10 : 12 : 13 : 14 : 15 : List 4 if ()p ニ maIIoc(B-SIZE)) p 「 intf ( " 確保できませんでした。 Yn"); exit(EXIT_FAI し URE) : printf(" 確保しました。 Yn"); exit(EXIT SUCCESS); ニ NULL) { : #include く stdio. h> #include く stdlib. h> 4 : #define B_SIZE 1024 * 64 6 : main() Char if ( sb 「 k ( 1024 * 36 ) printf ( " 拡大できませんでした。 yn"): exit(EXIT_FAILURE) : if ()p ニ naIIoc(B-SIZE)) - ニ NUL い { printf ( " 確保できませんでした。 Yn"): exit(EXIT FAI し URE) : printf(" 確保しました。 yn"): exit(EXIT_SUCCESS) : / * プログラム中 * / 12 : 9 : 8 : 5 : 3 : 2 :
元の数の符号性を継承しない , たんなる らず , 大きなデータの上位ビットはつねに ータの上位ビットが、、 1 〃て、うずめられます。 機械的な乗せ方を「 0 拡張 ( zero extend) 」と呼 つまり , これによってデータの幅が大きく ヾ 0 〃て、うずめられます。 びます。こちらは , 元の数の正 / 負にかかわ なっても , 負数は負数て、す。 上に述べたように , char 型 ( サイズ = 8 ビ ット ) はデフォルトて、は有符号数なのて , ラ KPIK. C ベル back: 以降の 3 行て、 16 ビット幅の変数 c0, cl に転送されるとき , 符号性が保存さ 1 : / * KPI K. C : OASYS のユーザ辞書のダンプファイルから , 登録語彙だけを抽出する * / れます。たとえば 0xnn という char の値は , 2 : / * (1) Jan. 1991 , H. lwatani ( 入出力は標準入出力のリダイレクトによる ) 3 : c0 または cl の上て , 元が正の値なら 0x00nn 4 : #include く stdio. h> 5 : #include く ctype. h> となり , 元が負の値なら 0xffnn となります 6 : #include く jctype. h 〉 ( 上位をヾ 1 〃て充填 ) 。 7 : 8 : / * お尻に付いているゴミ #define Nonsense に並んている漢字は , 9 : #define Nonsense(c) ( c = 0X955f Ⅱ c = 0X915f コードの上位バイトも負数てすが , これは c==0x9abe cx の上て下位バイトと合成されるとき 8 ビッ c==0x9c5f c = 0X975f ト左シフトされるのて , 上位の 0xff は消えて 14 : c==0x9bbe c==0x90be しまい , 問題ありません。 c==0xea5f c==0xe0be) しかし cl に転写された時点の下位バイト は , それが負数なら 0xffnn< あり , それが , 19 : ・ m a i n ( ) 20 : { シフトされた c0 と OR 演算されるのて、すか 22 : ら , cx 上に見事に ( ? ) , 0xff.. が残ってしま います。したがって , ういう値は 24 : 25 : if(Nonsense.. て、偽となり , 捨てられずに出力 26 : 27 : されてしまいます。 28 : 29 : char が有符号数だ このことはひとえに 30 : から起こるのて、あり , だから char を無符号 32 : 数にしてしまえば解決します。たとえば Turbo 33 : 34 : C コンパイラの起動オプションて、ある、、一 K 〃 35 : を使用します。 36 : back: OASYS. TST(List 2 ) は , 上記のことをデ 38 : 39 : モるためのテスト用の超小型辞書ダンプフ 40 : ァイルて、す。そしてー DDBUG 〃オプション 41 : #ifdef DEBUG 42 : printf( " % 04X % 04X %04xYn" て、コンパイルした場合の出力が , signed. out 43 : #endif 44 : (Fig. 1 ) と unsigned. out (Fig. 2 ) て、す。いう i f ( Nonsense( (unsigned)cx ) ) { 46 : * ( bufptr ー / * 文字列終端子を後退してゴミ退治 * / まて、もなく , 後者が , 、、一 K 〃オプションて、コ bufptr ー = 2 : / * 新たな尻へ * / ンパイルしたときの出力て、す。 48 : if( bufptr 〉 = buf ) goto back; char 型 ( 文字型 = 文字を表す ) データが有 符号数だ , というわれわれの日常常識に反 52 : する C のデフォルト設定から , ときどきこう 53 : 54 : いうドジが生じます。 55 : 56 : } 先日 , 拙訳の「 TurboC による人工知能」 ( に学社 ) 中のプログラムて , 日本語を入力 List i nt c0 , c 1 , cx : char buf[ 240 ] : char *bufptr; wh i I e ( ( c0 = getchar ( ) ) ! = EOF ) { i f ( i skanj i ( c0 ) ) { bufptr = buf; do{ = getchar() : *bufptr 十十 c0; *bufptr 十十 = cl : } while( iskanji( c0 ニ getchar() *bufptr ungetc( c0, stdin ) : / * 尻のゴミを再帰的に処理 * / = * ( bufptr-2 ) : = * ( bufptr-l ) : ( c0 くく 8 ) ー cl; 0 1 よ / * 16 ヒ・ツト を合成 * / int c0, cl, cx ) : if( strlen( buf ) ) puts( buf ) : 84 C MAGAZINE 1991 4
ますが ) 。 OASYS に関して入手てきるその 種の情報は , ほとんどゼロといってよいて、 しよう。てすから , サードバーティのソフ トハウスなどて、も , OASYS 用ューティリテ ィをなかなか手がけないのてす。 いい換えれば , OASYS のシステム世界へ ( から ) は , 一般人が通行て、きるための道も 橋もまったく整備されていないのて、す。 辞書共通化の試み 私が使っている PC ー 98 には , 某社製の親指 シフトキーポードが付いていますが , ては なぜ日常の日本語文章作成にパソコンを使 わないか。それは , 「パソコン用日本語ワー プロソフトの使い勝手の悪さ十モニタ画面 の文字の見づらさ」のゆえてす。 パソコン用日本語ワープロソフトが , も っと独自の思い込みの少ない , スッキリし た出来になり , そしてモニタ画面が , 今の NeXT 並みの精細さになれば , もう , OASYS にかぎらず , ワープロ専用機というものを 使ってはいないてしようね。 しかし現在ても , パソコン上て , たとえ ば C 言語のソースは書くし , それのコメント 文などとしてけっこう大量の日本語を入力 することがあります。 しかし , 日本語環境としての利用頻度は , OASYS のほうが圧倒的に高いのて、 , 辞書は OASYS のほうが充実していきます。ワープ ロの本来の辞書がサポートしていない漢字 熟語ばかりて、なく , たとえばヾペ〃を変換す るとヾオペレーティングシステム〃とか , ぶ〃 を変換するとヾプログラム〃などのたぐいの 「便利性」も帯びてきます。 そうすると , 当然のことながらパソコン 上て日本語入力するときは , 辞書が不便に 感じられます。 最初は , OASYS 上のユーザ登録語を , そ れらの変換用入力語 ( 上記のヾペク , ぶ〃など ) とセットて , 自動的にパソコンの FEP の辞 書に転送するユーティリティを作ろうと大 士を抱きました。 今使っている某 FEP の辞書を DUMP して みましたが , どうもその設計思想がダンプ リストからは読み取れません。大志は挫折 そこて普通に , 手入力によってパソコン 側の辞書を OASYS と ( ほば ) 同一化しようと いう方針にしました。 OASYS のシステムディスクのどこに辞書 のユーザ登録語の部分があるか , それはデ イスクの内容をダンプすることによってわ かりました。 しかし , その部分をダンプした内容は , 目的とする語彙だけてはなく , その前後に 意味不明の管理情報やら制御情報らしきも のがズラズラと入っています。すなわち , OASYS 側の辞書の設計思想も , ダンプリス トを見ただけて、は不明てす。 語彙の前後にくつついている余計な情報 を捨てて , 語彙だけを取り出す簡単な道具 を作ろうと思いました。これが , 今回の「ド ジ」への入口てす。 厄介な有符号数 List 1 を見てください。これは , KPIK ℃ という , ほとんど誰にとっても実用価値の ないプログラムてす。 while 文の次の if 文ておわかりのように このプログラムはまず漢字 ( 平仮名 , 片仮名 なども含む ) にだけ着目し , ASCII コードな どは捨てます。 て , 漢字コードは , それが続くかぎりバ ッフアに拾っていきますが , ほとんどの語 彙の末尾に , 何らかの管理情報がたまたま 漢字コードと同じ値だったために生じた ( と 思われる ) ヘンな漢字がくつついています。 それらが , #define Nonsense(c) に並んてい る 9 個の漢字てす。これは , 捨てなければな りません。 そこて , back: というラベル以降て , その 処理をしています。 goto 文を使うという安 直て、ダーティーな方法は , こういう , 自分 だけしか使わない小さな道具ては ( 拙速を重 んじるため ) よくやります。 #ifdef... #endif の中の printf( ) 文は , 今回の 話の目的のために付け加えたものて、す。変 数の値を 16 進数表記て出力します。 変数 c0 と cl に , 語彙の末尾の漢字コード を拾い , それを変数 cx の上て一本化してい ます。その cx の値を , # endif の次にある if(Nonsense... て、チェックしています。そし て無用な漢字ならば捨て , ラベル back に戻 ってさらにまた末尾のチェックを繰り返し ます。 こうして , ひとつの語彙の出力は , 最後 の puts ( ) て行われます。これをダンプファイ ルの終わりまて、繰り返します。 ところが , 現状のコードては , 捨てたは ずの余計な漢字が , お尻にくつついたまま 出力されることがあるのてす。 9 個の漢字 ( 廟 , 狙 , 埓 , 彑 , 誉 , 崟 , 誓 , 鸚 , 狎 ) のうち , 廟 , 狙などは OK てす。ね らいどおり捨てられています。ダメなのは , 埒 ( 埒の占字 ) , 崟などてす。 #define Nonsense を見ると , 捨てられな いて , 尻に残って出力されてしまう漢字は , そのコードの第 2 バイトを有符号数として見 るならば負数てす。 そして C の char 型は , キャラクタ型 ( = 文 字型 ) という名称にもかかわらず , デフォル トては有符号数てす。 幅の狭い ( = ビット数の少ない ) データを , 幅の広い ( = ビット数の多い ) データに乗せ るとき , 元の数の符号性 ( すなわち正か負か の別 ) を正しく継承する乗せ方を「符号拡張 (sign extend) 」と呼びます。 符号拡張においては , 負数は , 大きなデ C 言語フォーラム 83