#include くファイル名 > システムて、定められたディレクトリて、 ファイルを探す #include " ファイル名 " カレントディレクトリて、ファイルを探 す というふたつの書き方があるのて、す。自分 て、つくったヘッダファイルを取り込むとき には , 後のタイプの # include を使います。 本来ならば「変数」の解説 ( ' 89 年 11 月 て、お話すべき内容だったのて、すが , 関数に ついての知識がないと実感て、きないのて、は ないかと思い , 今回まて、延期してきました。 6-6-1 記憶クラス C て、は変数や関数の性格を決定するために データ型と記憶クラスを用います。型はデ ータのサイズを規定するのに対し , 記憶ク うのもひとつの手段かもしれません。この プログラムにも出てくるような決まり切っ 点については , 機会があった時点て、解説し ラスはデータがメモリ上のどこにとられる た処理が出てくることがあるかと思います。 かを規定するものて、す。さらに記憶クラス ましよう。 そのような処理は関数にしてしまい , 独立 の指定がされている位置 ( 関数の内とか外 ) ところて、①のファイルて、 # include が見な したモジュールにしてしまったらいかがて、 しようか ? さらに本誌 ' 89 年 11 月号の特集 によって , その変数の通用範囲 ( スコープ ) れない形をしていますね。実は今まて、出て が決まります。 にもあったようにライプラリを作ってしま きませんて、したが , 変数の宣言は 型宣言子変数名の並び Fig. 3 記憶クラスを考慮した関数の形 という形て、行うという話は以前にしました 〇タイプ 1 が , 今回記憶クラスを導入しこれを拡張し てみましよう。 関数名 ( 引数型宣言並び ) 記憶クラス指定子型名 記憶クラス指定子型宣言子変数名の 関数内変数宣言 並び このようにいちばん先頭に記憶クラスの 実行文 指定をします。関数に記憶クラスを指定す る方法が Fig. 3 て、す ( タイプ 1 のみ記述 ) 。ま た , 記憶クラス指定子の種類を Fig. 4 に示し 6-6-2 変数の記憶クラスと 範囲 変数は記憶クラス指定子と宣言の位置に よって通用範囲が決まります。記憶クラス SpIit1 'a 2 : 分割コンパイルの例 3 : ma i n 関数部分 5 : #include く stdio. h> 6 : #include ” splitl ・ . h" 7 : 8 : void main(void) 12 : 13 : } / * sp ⅱ t 1 ・ . h を読み込む * / printf(" 1 + 2 +. summation(n)); . + %d = XdYn ” Split1'b 分割コンパイルの例 2 : 総和の計算をする関数部分 3 : int summation(int n) 5 : 7 : int i, tmp for (i 9 : tmp 十ニ i : return (tmp) : Fig. 4 記憶クラス指定子の種類 スタック記憶クラス指定子 autO レジスタ記憶クラス指定子 register 静的記憶クラス指定子 static 外部記憶クラス指定子 extern 型定義指定子 typedef ※ typedef は , 構文的な都合から記憶クラス指定子と呼はれる 機能は異なり , 型の同義語を作る 120 CMAGAZINE 19 3
0 「 m 面 00 from ( 0 pi 「 ma 「 5 gd = PC98 : gm = PC98C8 ; initgraph(&gd,&gm, " ) ; FMR シリーズて、は , ノーマルモ ード用の BGI ファイルをハイレゾモ ードて、使うことはて、きないのて、 , DETECT を指定しておくのが望ま しいて、しよう。この場合 , FMRM. BGI と FMRH . BGI を用意してお きます。 FMRL. BGI は直接指定し ないかぎり使用されません。この 場合 , 画面の大きさが異なるのて、 , 必要に応じて getmaxx( ) , get maxy( ) などの関数を使って画面 の大きさを取得しておくとよいて、 しよう。もちろん , ノーマルモー ドとハイレゾモードを別々のプロ グラムすることもて、きます。 こうしたプログラムて、は , 実行 ファイルとは別に BGI ファイルを置 いておく必要があります。 MS-DOS Ver. 3. x て、は , プログ ラムが起動したディレクトリやフ ァイル名を取得て、きますのて、 , プ ログラムの起動ディレクトリから BGI ファイルを呼び出すためには , List2 のようにしてプログラミング て、きます。 BGI ファイルをプログラム自身に 組み込んて、しまいたい場合は , BGIOBJ ユーティリティを使って BGI ファイルを . OBJ ファイルに変 ティレクトリやファイル名を取得 List 2 List 3 BGI ファイルをプログラムに組み込む場合 initgraph (&gd, &gm. bgidir); DETECT : fnmerge (bgidir, drv, dir, NU しし fnsplit (argv[0], drv, dir, file, int gd, gm; char drv[MAXDRIVE], dir[MAXDIR], char bgidirCMAXPATH] : main (int argc, char **argv) #include く graphics. h> #include く dir. h> NULL) : ext) : file[MAXFILE], ext[MÅXEXT] : 換し registerbgidriver を使ってプ ログラムにリンクします。特定の BGI をリンクするのて、あれば , regis terbgidriver が返した値とグラフィ ックスモードを指定します (List3)0 このときに , DETECT を 使って最適のグラフィックスドラ イバを検出したい場合は , すべて の BGI を組み込んて、おきます。 これらのフォントを頻繁に切り 換えるときは , 切り換えるたびに フォントファイルの読み込まなけ ればなりません。フォントファイ ルは , BGI ファイルと同じように Bouttext などて、 , ストロークフォ ントを使う場合は , settextstyle て、 フォントの指定 #include く graphics. h> main() List 4 int gd, gm: DETECT : initgraph (&gd, &gm. settextstyle (GOTHIC_FONT, フォント名を指定します (List4) 。 GIOBJ と registerbgifont を使って 実行プログラムにリンクて、きます。 こうしておけば , フォント切り換 えのたびにファイルにアクセスす る必要がなくなり , スムーズに切 り換えることがて、きます (List5) 。 住所変更された方へ 弊社からお送りしているアップ デートのご案内て、 , 転居先不明て、 戻ってくるものがかなりあります。 住所変更された方は , 必ずサポー トセンターにご連絡ください HORIZ_DIR, #include く graphics. h> main() int gd, gm; reg isterbgidriver if ()d くの abort(); PC98C8; gm ini tgraph (&gd. &gm, (PC98_driver): フォントファイルのリンク #include く graphics. h> main() List 5 int gd, gm; lnformation from Compiler Makers 137 in i tgraph (&gd, &gm, DETECT : if (registerbgi font (SMAL し _PONT) くの abort() : if (registerbgi font (GOTHIC_FONT) く 0 ) abort() :
五ロ 用 応 ことがて、きます。たとえば , カーソルの位 置づけて、は , カーソルの座標 ( X , Y ) を指定す ることがて、きます。 カーソル位置づけの ESC シーケンス ( ESC CpI ; pcH) は , 次のような文字列として出 力します。 x = 0 , Y= 10 とすると , 次のよ うになります。 char param [ ] [ 表 3 ] colo 「バラメータ define 名 List 9 バラメータ 0 7 ・・乙 - LO 定転線滅 既反下点赤青紫緑黄水白 0 日 G REV IJNDER 日凵 NK RED BLIJE PIJRPLE G 日 EEN YELLOW SKY WHITE CO ー 0 「 1 : 2 : / * col or 3 : 4 : color (char *attr. char * C010r - no ) VO i d param ロ ={ESC, ・ [ ・ 6 : static char 7 : param [ 2 ] =*attr; 8 : / * 表示属性 * / param[4]=*color-no; / * 表示色 * / 9 : param[5]=*(c010r-no + 1) : printf("X. 7s", param) : return; 13 : } 属 性 りし CO 1 / 8 0 りし Cu 0 し Cu 表示色 X 座標 Y 座標 これを CRT へ出力すれば , 指定した位置 にカーソルが位置づけられます。 サンプレプログラム サンプルプログラムは , 各関数のテスト 用のプログラムを内蔵しています。メニュ ーに従って , 操作すれば , 各関数のテストが て、きるようになっています。いろいろと , 自作の関数を増やしてください それて、は各関数を解説しましよう。 csr posit( カーソル位置づけ ) カーソルを任意の場所に位置づけます。 「 ESC = lc 」を使用しています。「 1 」 ( Y 座 標 ) , 「 c 」 ( x 座標 ) は , それぞれ 2 進数て、オフ セット 20H を加えた値て、す。 X 座標は , 0 ~ 79 まて , Y 座標は 0 ~ 24 ま て、となっています。以下 , XY 座標を指定す る関数は , この範囲て、指定してください たとえば x = 5 , Y= 10 とすると , 次のよう になります。 rnaln LlSt 1 0 1 : #include く i 0. h> 2 : # i ncl ud e く stdio. h> 3 : #include く string. h> 4 : #include く stdlib. h> 5 : #include く sysytypes. h> 6 : #include く sysYstat. h> 7 : 8 : #define ESC 0x 1 b 9 : #define B 亂し 0X07 11 : #define ORG 12 : #define REV 13 : #define UNDER 14 : #define B い NK 16 : #define RED 17 : #define B し UE 18 : #define PURP し E 19 : #define GREEN ” 20 ” 20 : #define YELLOW ” 21 ” 21 : #define SKY 22 : #define WHITE 23 : 24 : VOid getxy(int *x, int (y) : 25 : VOid csr-posit(int x, int y) : 26 : VOid put-str(int x. int y,char *buf, int cnt) : put-chr(int x, int y,char chr) : 27 : VOid cls(void); 28 : void clear(int y); 29 : VO i d char param [ ] {Ox1b, ' ' , Ox2a , 0X25 } ・ X 座標 Y 座標 応用 C 言語 101
三田典玄の 実践 C プログラマ 第 0 回 C 言語とシステムエンシニアリング 養成講座 List 3 80 : END ds,ax to DATA-SEGMENTS 42 : { 49 : 50 : 52 : 53 : 54 : 55 : 57 : 58 : 59 : 60 : 62 : 63 : 64 : 65 : 66 : 68 : 69 : 73 : 74 : 77 : stpintr 78 : KEYINTS_TBXT _cpyintr -cpyintr 56 : PUB い C popf iret ENDP -cpyintr PROC FAR ENDS ENDP iret sti pop f POP POP mov mov 田 OV mov push push pushf c ⅱ マクロが呼ばれる直前に押された とを示す。 このマクロを参照することによって HIT—COPY の値は FALSE にクリア される。このマクロへの値の代入は て、きない #include ″ keyint. h& 0 a X ds ax, 1 ds: ds f_copy, ax ax, DGROUP : Set DS: Set Not 0 BOOL PC98RomBiosBasedKbhit( ) ; 標準ライプラリにある kbhit ( ) 関数と 同じ。 MS-DOS の入力モードを変えずに 十などのキーデータも取 れる。 #include 〃 keyint. h" Keyget. c List 4 int 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 11 : 13 : 25 : 31 : 32 : 33 : 39 : 40 : 43 : 44 : 38 : #define 37 : #define 36 : #define 35 : #define 34 : #define #define #define 30 : #define 29 : #define 28 : #define 26 : #define 24 : #define 23 : #define 22 : #define 20 : #define 18 : #define 17 : #define 16 : #define 15 : #define 14 : #define 12 : #include #include 10 : #include ROM-BIOS Based Kbhi t ( ) & Getch ( ) funct ions Created by N. Mita (CoreDump CO, . Ltd. ) Copyr ight 1987 CoreDump CO, . し td. PC98RomBiosBasedGetch( ) ; 標準ライプラリにある getch ( ) 関数と 同じ。 MS ー DOS の入力モードを変えすに 十などのキーデータも取 れる。 く conio. h> く dos. h> く stdio. h> READ_BUFF SENS_BUFF SHIFT_SENS KBD_INIT SENS_INKEY INT_KEY_BIOS DoInt TRUE FALSE B00 し S_CTR し _Q S_CTR し _S S_CTR し _N S_CTR し _P S_CTR し _C C_CTR し _Q C_CTR し _S C_CTR し _N C_CTR し _P C_CTR し _C 0 1 2 3 4 0X18 int 0 1 / * Boolean constants * / ()O (d) int86x(INT_KEY_B10S, &inp-reg, &out-reg, &seg-reg) 0X2B03 0X1910 0X2E05 0XIE13 0X1011 0X03 0X10 0x0E 0X13 0X11 41 : B00 し PC98RomBiosBasedKbhit() struct SREGS seg_reg; inp-reg. out_reg. union REGS これらのマクロを通常の標準ライプラリ と同じ手順て、呼び出せるようにする方法は , MS ー C の付属マニュアルの「 LIB. EXE ライプ ラリマネージャの使い方」の項に詳しく載っ ているのて、ここて、は説明しない また , これらの関数はすべて LARGE/ HUGE モデル用て、ある。コンパイル時には 「 /AL 」フラグをつける必要がある。 関数 ( マクロ ) の説明 実銭 C プログラマ養成講座 93 PC ー 9801 シリーズて、はキーポードからの入 するものて、ある。 るもの , もうひとつは通常のキーの操作を ひとつは一 / ーキーの操作をす 関数 ( マクロ ) 群はふたつに分かれている。
るが , 潜在的な問題がひとつある。それは , 基本クラス hashtab 型のポインタや参照さ れた変数を使用するとき , 導出クラスのな List 4 HASHTAB . HPP かて、同じ名前のメンバ関数は使用て、きない ということて、ある。基本クラスて、関数を仮 想しておき , この問題をうまく避けようと 1 : #define DEBUG_HASHTAB 3 : / / hashtab. hpp - ノ、ツシュテ 4 : class hashtab { size_t tablesize; S i ze_t inserted; void **table; 23 : 20 : 9 : 8 : 7 : 6 : 5 : ープルのクラス定義 / / 実際のテープル / / 挿入した要素の数 / / テープルのサイズ s ize-t (*map) (VOi d *element) : int (*compare) (void *el, void *e2) : size-t -lookup(void *element) : 12 : public: hashtab(size-t tablesize, si ze-t (*map) (void *e lement) . int (*compare) (void *el, void *e2)) : / / キーからテープルのインデックス への写像関数 / / strcmp にしたがってふたつの要素を比較 / / 内部検索関数 hashtab()o (d) { delete table: void *lookup(void *element) : VOid insert(void *elenent) : VOid remove (VOid *e lement) : 22 : # if defined (DEBUG_HASHTAB) & & def ined (__ZTC__) void dump-tab(void (*d) (void (e)) : 24 : #endif List 5 HASHTEST. CPP / / ほとんどの部分のデータ型をこれで修正できる typedef unsigned size_t; #include く stream. h> 4 : #if !defined(_-ZTC--) 2 : / / hashtest. cpp ー汎用ハッシュテープルクラスを試す 3 : 5 : 6 : 9 : 12 : 15 : 19 : 20 : 22 : 23 : 24 : 30 : 33 : 13 : #include "hashtab. hpp" #include く ctype. h> 10 : #end i f #include く stream. hpp> 8 : #include く stdio. h> 7 : # se / / データ型 size ー t を用いる size-t imap(void *element) { return *((int *)element) : int icompare(void *el,void *e2) { i f ← ( i nt * ) e 1 > * ( i nt * ) e2) return 1 : else if(*(int の el 32 : #endif cout くく *(int の el : 29 : void idisplay(void *el) { 28 : # if defined (DEBUG_HASHTAB) & & defined (__ZTC__) return -1 : e ー se return 0 : しても , C 十十て、は導出クラスのなかて、仮想 関数の型の再定義をすることはてきない したがって , 導出したハッシュテープル のオプジェクトをさすポインタを , ハッシ ュテープルのポインタとして割り付けて使 用することはて、きない。しかしながら , の禁止は煩わしいものて、はない。それは , 一般的にハッシュテープルの実体 ( ins tance, Smalltalk ー 80 て、はインタンスと呼ぶ ) に対して多様なアクセスを必要としないか らて、ある。多様なアクセスを行う理由を ( へ そ曲がりて、なく ) 考えついたならば , ぜひ教 えていただきたい inttab クラスはありふれた例て、ある。オ プジェクトの中のデータがキー ( key ) だけの 場合 , LOOKUP 関数はプーリアン関数 (Boolean function) に退化する。そのとき はテープルから何も検索しない。つまり , 格納されているものが検索のために与えら れたキーそのものだけなのて、 , すて、にその キーがあるかどうかを調べる ( 0 か 1 かを返す ) データを検索することにも , 複合的な hash る。複数のキーを用いてテープルから対象 class) に hashtab を変えていくこともてき ている結合配列クラス (associative array graming LanguageJ ( 文献 [ 2 ] ) て、論じられ てきる。 Bjarne Stroustruph の「 C 十十 Pro ータとして ,hashtab の変数を使うことも イスをもっクラスのためのプライベートデ する代わりに , まったく異なるインタフェ tab から新しい導出クラス (subclass) を導出 クラスの使用法にこだわる必要はない。 hash - とはいっても , 筆者が例示した hashtab れる絶好の例なのて、 , あえて用いた。 クラスを用いてて、きるアイデアを与えてく いるべきて、ある。しかし , inttab は , hashtab 理想的にはメモリアロケーション技術を用 プジェクトを取り扱う場合には効率が悪い めに演算子 new を使用することは , 小さなオ ぞれのテープルのエレメントを生成するた だけて、よいというわけてある。また , それ ァープルのなかのテープル 27
インドウにアイコンをセットします。 子ウインドウふたつは , それぞれ Win SetWindowPos( ) により適当な初期位置 にセットされ表示されます。 子ウインドウごとに用意したローカルデ ータ領域を子ウインドウ関数からアクセス て、きるようにするために , WinSetWind owPtr( ) て、子ウインドウの予約メモリへロ ーカルデータ領域のポインタをセットしま す。また , 子ウインドウのメニューがクリ ックされたか ( 実処理が始まったか ) どうか を示すフラグとして用意した予約メモリ内 の unsigned short(QWL USER USHO (T) に WinSetWindowUShort( ) て、 FAL SE ( 実処理はまだ始まっていない ) をセット 川 : SWP 30 : 29 : 28 ! 26 : 25 : 22 : 20 : 16 : 9 : 7 : 6 : 5 : 4 : 3 : List 2 HWND 8 : HAB # include 鉢 include # include # include 2 : #define ・ #define smp. C INC い DOS 'INCL_WIN く 0S2. h> <stdio. h> く process. h> - snp. h" II : HMODU し E FAR habMain; hwndhain: swpMain; hnodDll : 13 : MRESU し T EXPENTRY HainClientWndProc(HWND. USHORT. MPARAM. MPARAM) : 14 : MRESU し T EXPENTRY ChildClientWndProc(HWND. USHORT. MPARAM. MPARAM) : int nain (void) static static static static HWND QMSG HMQ hnq; static static U し ONG ULONG qnsg: CHAR CHAR flMainPlags : FCF_TIT し EBAR FCF_SYSMENU FCF_SIZEBORDER FCP_MINMAX FCP_SHE しし P0引ロ0N FCP_MINBUTTON; FCP_MENU PCF_SIZEBORDER FCF_SYSMENU FCF_TIT し EBAR flChildFlags = FCP_TASK い ST,• します。 WinTerminate( ) て、リソースを解放して , Queue( ) てメッセージキューを破壊し , インウインドウを破壊し , WinDestroyMsg プを抜け出し , WinDestroyWindow( ) て、メ というメッセージを受け取ると , このルー メッセージ処理が始まります。 WM QUIT によりメッセージループを形成し , 実際の WinGetMsg( ) と WinDispatchMsg( ) WM SIZE ジごとに説明します。 れたメッセージを処理します。 こてはメインウインドウに対して送ら くメインウインドウ関数 > このプログラムは終了します。 各メッセー ウインドウのサイズが変更されると , 32 : 33 : 34 : 35 : 36 : 38 : 39 : 40 : 42 : 43 : 44 : 46 : 49 : 50 : 52 : 55 : 56 : 58 : 59 : 60 : 63 : 64 : 65 : 66 : 68 : 69 : 73 : 78 : 79 : 82 : 83 : 84 : 86 : 88 : 89 : 90 : 92 : 93 : szMainCIass[] szChiIdCIass[) ” Wnd8Parent ”・ "Wnd8Child" ・ hwndPrane. hwndFramel, hwndPrame2, hwndClientl, hwndClient2,• WORK FA し SE. XPOSITIONI, YPO 引 ON し 0. 0 , TIMERI, SZTEXT l. NU しし 0 し 0 し 0. 0. 0. 0 , 0. NU しし 0. NU しい : YORK PA し SE, XPOSlT10N2, YPOSIT10N2, 0 , 0. TIMER2, SZTEXT2, NU しし 0 し 0 し 0. 圧 0 物 0. 0. N 乢し 0. NU しい : NU しし NU しし . のメッセージがきます。 こて、は , メイン ウインドウのサイズをつねにサンプリング するために , このメッセージを受けて Win QueryWindowPos( ) てサイズを swpmain に取り込んて、います。 WM PAINT ウインドウを再描画する必要があるとき このメッセージが出ます。 こては habMain = WinInitialize( の : CS_SI ZEREDRAW, ChildClientWndProc, szChildClass, habMain, WinRegisterClass( CS_SIZEREDRAN, MainClientWndProc, szMainClass. habMain, NinRegisterClass( hnq = WinCreateMsgQueue(habMain, szChildClass. &flChildFlags, WS_VISI B し E, hwndMain, hwndFranel = WinCreateStdWindow( &hyndMain) : 0. NU しし szMainClass, &flMainPlags. HS_VISI B し E. HWND_DESKTOP, hwndFrane = WinCreateStdWindow( sizeof (PVOID) + sizeof (USHORT)) : WinBeginPaint( ) て、取得したキャッシュプ レゼンテーションスペースを使って GpiEr ase( ) てメインウインドウのクライアント描 画領域をクリアしています。キャッシュプ レゼンテーションスペースは , WinEn 52 CMAGAZINE 19 3
を i 物 i れ Tab 5 このもっとも望ましい性質は , PI ー P2 = 2 という特性をもつふたつの素数の場合に得 られる ( その理由はこの記事のなかて、は取り 扱わない。クヌースの文献を参照してほし LOOKUP は INSERT の論理に従ってい る。 2 次ハッシュ値を加算して得られた 連のアドレスは , 特定の対象データに対す る衝突リスト (collison list) と呼ばれる。ひ とつの対象データを検索するには , この衝 突リストに従って , 対象データあるいは空 のスロットをみつけるまて、調べていく になる。 プレント法 プレント法 (List2) は LOOKUP 操作の時 間的複雑さを最適化する方法て、ある。特定 のアプリケーション ( とくにコンパイラ ) に とって , LOOKUP を行う回数は INSERT の 回数に比べて圧倒的に多い。プレント法は , こうしたアプリケーションのために , LOO KUP に最適なテープルを作成し , 高速検索 を可能にするが , 逆にテープルのなかにオ プジェクトを挿入するときには , 時間を費 やしてしまう欠点をもっている OC 十十によ る実現例を List3 に示す。以下に , INSERT に関するプレント法の説明を行う。 最初に , 挿入する対象データの衝突リス トの長さを計算する。その長さが 2 より小さ い場合は , 単純にその衝突リストの最後に 対象データを挿入する。 衝突リストの長さが 2 より大きいときは , リスト中のおのおのの要素を調べる。はじ めの要素について , その衝突したアドレス に格納されている対象データのリスト ( 挿入 しようとする対象データの衝突リストとは 異なる ) を調べ , そのリストの次が空て、ひと つの移動を要するだけなら , 格納されてい るほうをそのリストに従って移動させ , 挿 入する対象データと置き換える。もし , BRENT. CPP List 3 13 : / / f i nd-tabs i ze は必要なテープルサイズより大きいふたつの素数を返す関数 11 : #include "hashtab. hpp" 10 : #endif 9 : # i ncl ude くⅱ m i ts. h> 8 : #include く stream. hpp> 7 : # 引 se typedef unsigned si ze_t : / / ここでほとんどの箇所の型の変更ができる 5 : #define UINT-MAX ((unsigned)-l) 4 : / / 古い Un i x は ANSI ヘッダをもっていない #include く stream. h> 2 : #if !defined(--ZTC--) 1 : #include く stdio. h> 3 : 6 : 14 : 20 : 22 : 24 : 26 : 29 : 30 : 32 : 33 : 34 : 35 : 36 : 39 : 40 : 42 : 43 : 44 : 50 : 54 : 55 : 56 : 59 : 60 : 62 : 63 : 65 : 66 : 17 : / / また , テープルサイズを小さくするために 100 単位でひとつを選んである 16 : / / ここにある素数の要素は対の素数のうち 2 だけ小さいほうである static size-t find_tabsize(size_t tabsize) { 5 , 107 , 227 , 347 , 461 , 569 , 809 , 1019 , 1151 , 1277 , 1427 , 1607 , 1721 , stati C unsigned primes ロ 51 : / / 38 : # 31079.3118L31319. 3151L3172L31847 , 29021 , 29129 , 29387 , 29567 , 29669 , 29879 , 3 圓 11 , 30137 , 30269. 30389. 30491 , 30839 , 27059. 27239 , 27407 , 27527 , 27689 , 27791 , 27917 , 28097 , 28277 , 28409 , 28547. 28661. 24917 , 25031 , 25169. 25301 , 25409 , 25577 , 25799. 25931. 26111. 26249. 26681 , 26861. 22481 , 22619 , 22739 , 22859 , 22961 , 23201 , 23369 , 23537 , 23669 , 23831 , 24107 , 24371 , 20747 , 20897 , 21011 , 2119L21317.21491.21599 , 21737. 21839 , 22037 , 22157 , 2227 し 18911 , 19079 靆 9181 , 19379 , 1954L 19697 , 1984 し 19961 , 20147 , 20357 , 20477 , 20639 , 16829 , 16979 , 17189 , 17291 , 17417 , 17579 , 17681 , 17789 , 17909 , 18041 , 18251 , 1852L 14387. 14549 , 14867 , 15137 , 15269. 15581. 15731 , 15887. 1606 し 16187. 16361 , 16631 , 1216L12377 , 12539 , 1282L13001 , 13217 , 13337 , 13679 , 13829 , 13931 , 1408L 14249 , 10427 , 10529 , 10709 , 10859 , 11057 , 11159 , 11351 , 11489 , 11699 , 11831 , 11939 , 12041 , 6659 , 6761 , 6869 , 7127 , 7307 , 7457 , 7559 , 7757.7877 , 8009 , 8219 , 8387 , 5099 , 5231 , 5417 , 5519.5639 , 574L 5849 , 6089 , 6197.6299.6449 , 6551 , 3461 , 3581 , 3767 , 3917 , 4019.4127.4229. 4337 , 4481 , 4637 , 4787 , 4931 , 1871 , 1997 , 2111 , 2237 , 2339 , 2549 , 2657 , 2789 , 2969 , 3119 , 3251 , 3359. 8537 , 8819.8969 , 9239 , 9341 , 9461 , 9629 , 9767 , 9929 , 10037 , 10139. 10271 第 return primes[i] 十 2 : if(tabsize く = primes[i]) for(i = 0 : i く PTABSIZ: i + + ) i nt i : define PTABSIZ (sizeof(primes)/sizeof(size-t)) cerr くく” 0ut Of memory in hashtab constructor" if(table = NU し L) { table = new VOid *[this->tablesize] : / / テープルの割当て find-tabsize(tablesize) : this->tablesize / / テープルサイズからもっとも近いふたつの素数を求める int (*compare) (void *el, void *e2)) { size-t (*map) (void *element), 53 : hashtab: :hashtab(size-t tablesize, 52 : / / hashtab クラスのコンストラクタ 49 : #define deleted ((void * ) 48 : #define empty ((void * ) の exit(-l); cerr くく "Table size t00 big!Yn ” exit(l); / / テープルの初期化 for(int i ー 0 : i く this->tablesize; table[i] = empty : i 十十 ) 24 CMAGAZINE 19N 3
beep. c List 1 19 : } else { outp( 0X37 , 0X07 ) : else if ( !strcmpi( av[l], outp( 0X37 , 0X06 ) : if ( !strcmpi( av[l], 5 : void main( int ac, char *av ロ ) #include く string. h> #include く coniO. h> #include く stdi0. h> 13 : 9 : 8 : 7 : 4 : 3 : 2 : 1 : printf( ">BEEP {on10ff)Yn" ) : printf( ”ブザーの ON / OFF 制御 \ n " ) : List 2 setbeep. C #include く conio. h 〉 1 : # i nc I ude く std i 0. h > す。以下は MS - C て、の定義て、す。 ・ inp( ) , outp( ) int inp(port) int outp(port, value) unsigned port ; int value ; ・ inpw( ) , outpw( ) int int inpw(port) outpw(port, word) unsigned unsigned port ; word ; ポート入出力 ・・・出力データ アドレス ・・・入出力ポート ポート入出力 ワード単位の ・・・出力データ アドレス ・・・入出力ポート 2 : 3 : 8 : 9 : 12 : 13 : 17 : 18 : 19 : 20 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : 7 : #define 6 : #define 5 : #define 4 : #define SYS_PORT_C ON OFF TIMER_I 0X37 0X06 0X07 0x3PDB 10 : void main( void ) Char int lon g unsigned int sp, sph, freq; clock; sp I ; pr i ntf ( " ビープ音の周波数の設定を行ないます。 Yn" ) : printf( " 周波数計算式 : Freq. = 245760 * clock クロック周波数 ( 20 , 16 , 10 , 8M2 ) printf( scanf( "%d", &clock ) : wh i I e ( c ! = pr i nt f ( " %n n の値を入力して下さい ( 1 ー 65525 ) : n [kHz]Yn*'n" scanf( "%u", &sp ) : spl = sp % 256 : sph = sp / 256 : outp( TIMER_I, (char ) spl ) : outp( TIMER_I, (char ) sph ) : outp( SYS_PORT_C, ON ) : freq = 245760 * clock / sp; : Xld[kHz]Yn" printf( "Yn Freq. printf( " この音でよろしいですか ? く y scanf( "%ls", &c ) : outp( SYS-PORT_C, OFF ) : freq ) : 0 r n > 表 1 に I/O ポートアドレスの例を示しま り , PC ー 98 本体のブザーを制御て、きます。設 ( アドレス 37H ) にある値を設定することによ 表 1 の項番号 6 のシステムボートの C ポート サンプルプログラム 1 て、割り込み機能を制御て、きます。 ートに値を設定したり , 値を読み出すこと ドレスが割り当てられていてます。このポ ープ用に 08H , OAH の計 4 つの I / O ポートア ローラ用て、は , マスタ用に 00H , 02H , スレ たとえば , 項番号 1 , 2 の割り込みコント て機能が決定されます。 ます。 A の値は任意て、あり , この組み合わせ す。 X のビットは不定て、通常は 0 としておき flash. c List 3 定する値は , それぞれ , ブザーを ON にしたいとき ブザーを OFF にしたいとき : Ox06 : 0X07 1 : # i nc lud e 2 : # i nc 1 ude 3 : # i nc 1 ude 4 : # i nc 1 ude 6 : #define 7 : #define 8 : #define 9 : #define 5 : く stdio. h> く stdlib. h 〉 く ctype. h> く conio. h 〉 0xD0 0xD2 0xD4 0xD6 / * Lattice では不要 * / て、す。したがって , C 言語の命令て、はそれぞ れ , ブザーを ON にしたいとき : outp( 0X57 , Ox06 ) ; ブザーを OFF にしたいとき : outp( 0X57 , Ox07 ) ; とすればよいのて、す。 ON / OFF の時刻や時 ワンポイントプログラミング講座 107
三田典玄の 実践 C プログラマ VOid 引数 , 戻り値はない #include 〃 keyint. h" 0 ds,ax Reset98StopAndCopyKey( ) ; LiSt 2 112 : } 1 10 : 109 : 108 : 107 : 106 : 105 : 104 : 103 : 102 : 101 : 100 : 98 : 97 : 96 : 94 : 93 : 92 : 89 : 88 : 86 : 85 : 養成講座 第 0 回 C 言語とシステムエンジニアリング = INT_COPY; inpreg. h. al = o-cpy-seg; / * Restore interrupt vector for COPY * / segreg. ds inpreg. X. dx = o-cpy-off; (void) int86x(INT_DOS, &i 叩 reg. &outreg, &segreg) : segread(&segreg) : inpreg. h. ah = SET_INT; inpreg. h. 引 = INT-STOP; = o-stp-seg: / * Restore interrupt vector for STOP * / seg reg. ds inpreg. x. dx = o-stp-off; ()O (d) int86x (INT-DOS, &inpreg, &outreg. &segreg) : Set98StopAndCopyKey( ) 関数て、 無効になったキーと一 キーの本来の機能を復活させ , Set98 StopAndCopyKey( ) が呼ばれる前 の状態に戻す。 引数 , 戻り値はない #include 〃 keyint.h& main() VOid Set98StopAndCopyKey ( ) : if(HIT_STOP) printf("STOPYn") : if(HIT_COPY) printf("COPYYn") : i f (kbh i t ( ) ) break; Reset98StopAndCopyKey ( ) : BOOL H 工 T STOP List 3 Set98StopAndCopyKey( ) 関数を 呼んだ後 , このマクロの値を確かめ ることによって , キーが押 されたかどうかを確かめることがて、 きる。 0 #include 〃 keyint. h" て、きない される。このマクロへの値の代入は HIT_STOP の値は FALSE にクリア このマクロを参照することによって とを示す。 マクロが呼ばれる直前に押された ことを示し , それ以外て、あればこの 値が FALSE て、あれば押されていない 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 20 : 23 : 25 : 26 : 27 : 29 : 30 : 32 : 34 : 35 : 36 : 38 : 39 : 40 : 42 : 43 : 44 : 45 : 46 : 47 : 48 : Keyints. asm STOP-Key / COPY-Key / Support Copyr ight (c) 1990 CoreDump CO.. Ltd. Created by N. Mita (CoreDump Co.. し td. ) Please Use MASM 5. 1 or later Åssembler part routines 12 : KEYINTS_TEXT 13 : KEYINTS_TEXT 15 : _DATA 16 : _DATA 18 : CONST 19 : CONST 21 : _BSS 22 : _BSS 24 : DGROUP EXTRN 28 : EXTRN 31 : KEYINTS_TEXT 33 : PUB い C SEGMENT ENDS SEGMENT ENDS SEGMENT ENDS GROUP ASSUM E f_stop:WORD f_copy:WORD TITLE SEGMENT BYTE PUB い C KEYINTS. ASM 'CODE' ENDS WORD PUB い C 'DATA ・ WORD PUB い C ・ CONST' WORD PUB い C 'BSS' CONST, _BSS, DATA CS: KEYINTS_TEXT, DS: DGROUP. PROC FAR -stpintr SEGMENT SS: DGROUP, ES: DGROUP BOOL HIT_COPY -stpintr c ⅱ pushf push push 凱 OV mov IOV mov POP POP ・ ds ax, 1 ds: f_stop. ax ax, DGROUP 92 Set98StopAndCopyKey( ) 関数を 呼んだ後 , このマクロの値を確かめ ることによってキーが押さ れたかどうかを確かめることがて、き 値が FALSE て、あれば押されていない ことを示し , それ以外て、あればこの CMAGAZINE 19 3 Set DS: to DATÅ-SEGMENTS Set Not 0
五ロ 一三ロ はじめて学ぶプログラー ニンク て、はありません。各バージョンの違いは次 のような点にあります。 ・関数定義の形が新しいか , 古いか ? ・関数の記述順序 ・関数型宣言の位置 6-4-2 関数の型宣言と 関数プロトタイプ こて、関数の型宣言ということばが出て きましナ 、 0 float average(int a, int b, int c); List10 の例て、は , この部分が関数型宣言文 にあたります。 関数の呼び出しを行う側ては , 原則とし てその呼び出す関数の型宣言をしておかな くてはいけないのてす。ただし , その関数 が関数を呼ぶ前に定義されていれば型宣言 は省略て、きます。関数を呼ぶ前というのは プログラムファイルにおいて , より前方に 己述されているということてす。例ては e と f が関数型宣言を省略て、きます。 さらにこの関数型宣言文には次の形態が 存在します。 ① float average(int a, int b, int c); ② float average(int, int, int); ③ float average(); このうち①と②は形の違いこそあれ , ま ったく同じ動作をします。これらは関数の 型の宣言と同時に , 引数の型チェックの機 構をもっています。すなわち関数 average は 3 つの int 型変数を期待し , 戻り値は float 型て、あることを明示しているわけて、す。 のような機能をもった宣言文を関数プロト タイプ宣言文と呼びます。これに対し③は 関数の型の宣言をするだけて、 , 引数の型チ ェックはて、きません。 関数の定義にはふたつのタイプがありま したが , それらの働きの違いについてよう やくここて説明することがてきます。実は Fig. 1 のタイプ 1 は , 関数定義と同時に関数プ ロトタイプの宣言も行うことがてきるのて す。ただしその関数は呼ばれる前に定義さ れていなくてはいけません。したがって , e のような形は冗長なものになっているわけ て、す。 List 1 Oc 2 : 4 : #include く stdiO. h> 5 : 6 : / * 皿 in 関数部分 7 : void main(void) 9 : int X, y, 2. 10 : f 1 oat f : 00000 ・ 000 、 0 、 0 、 float b, int 12 : = 100 : y = 85 : 2 = X = average(), y, 2 ) : f printf("ans = XfYn" 18 : / * 3 つの整数の平均値を返す関数 ( タイプ 1 ) average(int a, int b, int c) 19 : float 20 : { float tmp; 22 : ((float)a + (float)b + (float)c) / 3.0 : 23 : tmp ー return (tmp) : 24 : 関数を使ったプログラム 省略できない List 1 Od 1 三ロ 2 : 4 : #include く stdio. h> 5 : 6 : 7 : / * main 関数部分 8 : void main(void) 12 : 14 : 19 : / * 3 つの整数の平均値を返す関数 ( タイプ 2 ) 20 : f loat int 22 : { 23 : 24 : 25 : 26 : 関数を使ったプログラム int x, y, 2 : f loat f : average(int a, float int i nt し ニ 100 : y ニ X average(), y. z) : printf("ans ニ %fYn" 省略できない average(). b, c) float tmp: ((float)a { (float)b + (float)c) / 3.0 tmp return (tmp) : List IOe 2 : 4 : #include く stdio. h> 5 : average(int a, int b, int c); / * 省略可能 * / 6 : float / * ma i n の中に入れてもよい 7 : 8 : 9 : / * 3 つの整数の平均値を返す関数 ( タイプ 1 ) average(int a, int b, int c) 10 : float float tnp; 関数を使ったプログラム はじめて学ぶ C プログラミング 117