printf - みる会図書館


検索対象: 月刊 C MAGAZINE 1991年3月号
22件見つかりました。

1. 月刊 C MAGAZINE 1991年3月号

五ロ はじめて学ぶプログラー ニンク 0 List 1 2 では , 解答者の中から 1 名の方の解答を紹介 します。 川窪功さんの解答 川窪さんの解答 ( List 12 ) は , 素直でわか りやすい解答となっています。川窪さんの 解答では , フォーマット文字を少し拡張し ています。フォーマット文字列に , ライン フィードを表す、、 n ″ , キャリッジリターン を表す、ア , スペースを表す、、 ' ' を追加し ています。また , 浮動小数点の出力のとき に , 出力する桁数の指定ができるようにな っています。 川窪さんの解答では , 出力に関数 putchar と関数 fputs のふたつを使っています。解答 の方針は , 最初に関数 pprintf の第一引数の フォーマット文字列に従い , va arg を用い て対応するスタックにアクセスします。そ して , 必要ならば数値を文字列に変換して , 標準出力に出力しています。 関数 pprintf は , ごく素直なコーディング をしているので , ほとんど説明の必要はな いですね。プログラムリストを目で追って いくだけでわかると思います。また , 直さ なければいけないような箇所もありません。 しいて細かいことをいうならば , 95 行目 で文字を出力するときに関数 putchar の中で va arg を char にキャストしていますが , こでは va arg を char でキャストする必要は ありませんね。なぜならば , char 型は , int 型にキャストされてスタックに積まれてい るからです。関数 putchar の引数は , int 型な のでそのまま関数 putcha 「で出力すればよい のですね。 こでは , 整数型を出力するときに一度 テンボラリ変数に代入し , その変数を文字 列に変換して文字配列に格納し , その文字 配列を出力していますね。しかし , 関数 itoa や関数は oa の返り値は , 文字列を格納してい 129 はじめて学ぶ C プログラミング 38 : 39 : int ppr intf ( const char *fornat, 40 : 42 : VOid nain( void ) 43 : { char c, s[ MAXBUF ] : 44 : int i; 46 : long に f loat f : 48 : double d; 49 : pri ntf ( コ nput Character scanf ( ” % c ” pprintf ( ” cnr", c) : printf()l nput String ・ scanf ( ” % pprintf("snr",s) : printf()l nput lnteger ・ 56 : scanf ("Xd" pprintf("inr",i); 58 : printf ( - lnput し ong lnteger ・ 59 : scanf("XId", ) : pprintf("lnr", l) : printf("lnput PIoat : scanf("Xf" f4: f5%nYr") : printf( ” format f: f3: 64 : pprintf()f f3 f4 f5nr ” ,f,f,f,f); printf("lnput DoubIe ・ scanf("Xlf", &d ) : pprintf("dnr", d) : pprintf()c s i ー f dnr ” , c, S, し 77 : 78 : i nt ppr intf( const char *format, va- list va-ptr; char type : char sbuf [ 50 ] : char ndig. int i,ival; long lval : float fva l; double dval : va-start( va-ptr, format ) : 90 : for ( i = 0 : (type = * fo 闥 at + + ) ! = ・ \ 0 ・ : switch ( type ) { 92 : 96 : 100 : 101 : 102 : 103 : 104 : / * 機能テスト用メインプログラム / * 桁指定チェック * / / * ストリング用パッファ / * 出力桁数 * / case を i nt ) ) : putchar ( (char) va-arg( va-ptr, break; case ー int ) : ival=va-arg ( va-ptr, itoa(ival, sbuf, 1 の : fputs (sbuf, stdout) : break; lval=va-arg ( va-ptr, long) : Itoa(IvaI,sbuf,10); 0

2. 月刊 C MAGAZINE 1991年3月号

いに対応させているが , MS-C および Turbo C は , これらのファイルのほかに ANSI 互換 の string. h を使用することもて、きるのて、 , string. h をインクルードすれば , #ifdef など が必要ないことになる ) 。 ・関数の機能 マニュアルなどに解説されている関数の 仕様は , 双方のコンパイラて、同一て、あって も実際にコンパイルしてみると , 機能が異 なっている場合がある。たとえば , cprintf がそうてある。 MS-C の場合 , List 4 のように #define を使 用して ,printf の代わりに cprintf を使用し画 面出力を高速化しても , 工スケープシーケ ンスは解釈されていた。しかし , Turbo C の場合には , それが解釈されず , コードが そのまま画面に出力されてしまう。したが って , Turbo C の場合には , printf のままて、 使用することが必要になる。 ・定数の問題 この定数の問題も , ひとつのコンパイラ pldwn. h textkei 2 . h 1 : / * 罫線関連の定数を定義 * / 3 : #define printf cprintf 4 : #endif 5 : 6 : #define S い NE 0X95 7 : #define D い NE 0xe0 8 : #define DLR D い NE 9 : #define DUDR D い NE + 1 10 : #define DCROSS D い NE 十 2 11 : #define DUDL D い NB + 3 12 : #define SOFTL 0x9c 13 : #define HARD し 0X98 14 : #define PSTUD 0xE4 15 : #define ENDUD 0xE5 16 : #define PSTLR 0xE6 17 : #define ENDLR 0xE7 18 : #define DFST し R OxE8 19 : #define DENDLR 0xE9 20 : #define UD 0X96 21 : #define LR 0X95 22 : #define LUKAGI 0X98 23 : #define RUKAGI LUKAGI + 1 24 : #define LDKAGI LUKAGI + 2 25 : #define RDKAGI LUKAGI + 3 26 : #define LUMÅRU 0x9c 27 : #define RUMARU し UMARU + 1 28 : #define LDMARU LUMARU + 2 29 : #define RDMARU LUMARU 十 3 30 : #define CROSS 0x8f 31 : #define LRU 0X90 32 : #define LRD 0X91 33 : #define UDL 0X92 34 : #define UDR 0X93 36 : #define UE 1 37 : #define NAKA 2 38 : #define SHITÅ 3 39 : #define YES 1 40 : #define NIJUYBS 10 41 : #define NO 0 43 : #define CLS printf ” \ 033 2J 44 : #define い NE20 printf - \ 033 3h 45 : #define い NE25 printf ” \ 033 3 ド 46 : #define CURON printf ” \ 033 47 : #define CUROFF printf ” \ 033 List 4 List 5 List 5 1 : #define RTI 1 2 : #define RT2 2 3 : #define RT3 3 4 : #define RT4 4 5 : #define RT5 5 6 : #define RT6 6 7 : #define RT7 7 8 : #define RT8 8 9 : #define RT9 9 10 : #define RTIO 10 11 : #define RTII 12 : #define RT12 12 13 : #define RT13 13 14 : #define RT14 14 15 : #define RT15 15 16 : 17 : #define B し ACK 0 * 0X20 + 1 18 : #define B し UE 1 * 0X20 + 1 19 : #define RED 2 * 0X20 + 1 20 : #define PURPLE 3 * 0X20 + 1 21 : #define GREEN 4 * 0X20 + 1 22 : #define SKY 5 * 0X20 + 1 23 : #define YE しし0W 6 * 0X20 + 1 24 : #define WHITE 7 * 0X20 + 1 25 : 26 : #define NONSEC 0X01 27 : 28 : #ifndef B い NK 29 : #define B い NK 30 : #endif 31 : #ifndef REVERSE 32 : #define REVERSE 0X04 33 : #endif 34 : 35 : #define UNDER し N 0X08 36 : 37 : #define FKI 0X001 38 : #define FK2 OX 圓 2 39 : #define FK3 0X004 40 : #define FK4 0X008 41 : #define FK5 0X010 42 : #define FK6 0X020 43 : #define FK7 0X041 44 : #define FK8 0X081 45 : #define FK9 0X100 46 : #define FKIO 0X200 48 : #define ERROR 49 : #define PYES 50 : #define PNO 52 : #define GR_SEG 0Xa800 53 : #define GR_OPF 0X0000 54 : #define MENUBUPFLEN 0X6000 55 : #define ATR_SEG MENUBUFFLEN / 0X20 56 : 57 : #define CLS pr intf("Y033[2J ” ) 58 : #define い NE20 pr intf("Y033[3h") 59 : #define い NE25 printf("Y033[31") 60 : #define CURON printf( ” \033[〉引") 0X02 108 C M AGAZIN E 1 1 3

3. 月刊 C MAGAZINE 1991年3月号

12 月号のクイズの解答 12 月号のクイズは , 「簡易 pscanf に対応す る Table 2 のフォーマット文字列をもつ簡易 printf を作りなさい。関数名は pprintf とす る。第一引数はフォーマット文字列のみと する。また関数 pprintf の動作を確認する簡 単な main 関数を作りなさい。このとき Tab 厄 2 のフォーマットをすべて含んだ例にするこ と」でしたね。 今回は , いつもより応募が少なかったよ うです。可変引数ということで , 少し難し かったかもしれませんね。 今回の出題では , 数値を文字列に変換す る部分に苦労するだろうと予想していまし たが , 自作で数値を文字列に変換する関数 を作った方はいませんでした ( AN の標準ラ イプラリ関数の中には , 数値を文字列に変 換する関数はないのです。このような関数 を定めていない AN 規格に不満の残るとこ ろです ) 。 int 型を文字列に変換するには itoa ( ) を , long 型を文字列に変換するにはは oa ( ) とい う処理系依存の関数を使っていました。 浮動小数点を文字列に変換するには , UNIX 互換の関数 fcvt( ) , gcvt( ) , ecvt( ) の どれかを使っていました。これらの関数は , 大抵の処理系にあるので , 移植性にそんな に問題はないでしよう。 クイズの解答によく使われていたライプ ラリ関数の説明を Table 3 に示します。それ 関数 pprintf のフォーマット文字 TabIe 2 Table 3 ・関数 ー用法 ■機能 クイズの解答によく使われていたライプラリ関数 itoa cha 「 * itoa( int value, char * str, int radix ) , 関数 itoa は , int 型の値 va ⅳ e を \ 0 ' で終わる文字列に変換しその結果を文字配列 st 「 に代入します。「 ad ⅸは , va ⅳ e を変換する基数を表します。 1 0 進数に変換するときには , radix= 1 0 とします。返り値は , 文字配列 st 「へのポインタです。 ・関数 ・用法 ・機能 ■関数 ■用法 ・機能 oa char * は oa ( long value, char * str, int radix ) : 関 toa は , 関数 itoa の long 型ノヾージョンです。 g cvt char * gcvt( double value, int ndec, char * buf ) : 関数 gcvt は , doub 厄型の値 va ⅳ e を \ 0 ' で終わる文字列に変化に変換して , その文 字列を文字配列 buf に格納します。関数 gc ⅵは , 可能ならば , FORTRAN の F 変換に従って nde c 桁の有効数字の文字列を生成します。 F 変換が不可能な場合は , p 「 in 廿の E 形式の文字列を生成 します。後ろに続く意味のない 0 は文字列に含まれません。関数 gcvt の返り値は , 文字配列 buf へのポインタです。 List 12 2 : 35 : 30 : 29 : 28 : 26 : 24 : 20 : 9 : 8 : 7 : 6 : 5 : 4 : 3 : 川窪さんの解答 ( pprintf. c) c 言語入門講座 9 0 年 1 2 月号課題 : MS=DOS Ver3. 30B OS function 簡易版 printf ppr intf. C lename Compiler Date Made by : TurbO C : 1990. 11.24 : 川窪功 ( 使用法 ) フォーマット 型 1 d int long float doub 厄 Char * Char (controll code) return 1 ine feed printf( ” s i d3nr ” , a, b, c) ( 例 ) ( * ) f,d は小数以下の桁数指定可 ( 例 : f3) 128 フォーマット文字 C MAGAZINE 1991 3 Char i nt long float double char * 型 ( 文字列 ) 31 : #include く stdio. h> 32 : #include く stdlib. h> 33 : #include く stdarg. h> 34 : #include く ctype. h> 36 : #define MAXBUP 128

4. 月刊 C MAGAZINE 1991年3月号

箱 応の 0 List 5 List 7 61 : #define printf("Y033[>5h") CUROFP 62 : #define CUR し EFT printf("Y033[lD") 63 : #define printf("Y033[lC") CURRIGHT 64 : #define し 0CATE(), y) printf("Y033[XdXdH", y, x) 65 : #define putchar( ・ \007・) MYBEEP 66 : #define putchar( ・ \ 036 ' ) HOME 67 : #define printf("Y033C>lh") BOTTOMOFF 68 : #define printf("Y033[>ll") BOTTOMON 69 : #define KANJI printf( ” \033)0 ” ) 70 : #define GRAPH printf("Y033)3 ” ) 72 : #define INITDT し 5 73 : #define MIDASHILEN 50 75 : #define PRT PR 1 76 : #define PRT MN 2 77 : #define PRTEPSON 3 78 : #define PRTCANON 4 40 : char att, 41 : int kind, int ura) : 42 : 43 : 44 : textkei3(int xl, 45 : int yl. 46 : int x2, int y2, char att, 49 : int kind, int ura) : 52 : 53 : dispkei2(int x, 54 : int Y, uns igned Char nark, char attr, i n t k i nd 58 : int ura : 60 : chgfnc3 (char oj i, Char color, int ura ) : 64 : printv( unsigned char str ロ . cha r attr int X, int y, int ura) : 70 : 田 i d ( char *ds, Char *SS, int start, int len ) : 76 : nypeek ( int sseg, int soff, char *dbuff, unsigned Size ) : 、 81 : nypoke( int dseg, int doff, char *dbuff, uns igned Size ) 86 : VOid iswap(int *p, int *q ) : 90 : inkey( void ) : 92 : realkey(int group) : 94 : scandir(int *pluskey ) : 96 : vranrd( int x, int y, Char *nark, char *attr, 100 : int ura ) : 101 : . vramwr( X, 102 ・ 103 : int y, 104 : Char *mark, 105 : char *attr, 106 : int ura ) : 107 : 108 : / * CM9009 * / 109 : superin2(int, int,char も int, 110 : i nt char, char,char.char, unsigned long も 113 : unsigned long, int) : 114 : int outforn(char も char も int) : 115 : int touppers char * 116 : i nt tolowers Char 事 117 : int nidins(char *,char も int): 118 : i nt nidtorup (char も int, i (t) : 119 : i nt spctoru char * ) : 120 : int locatec int. int) : 121 : i nt keyget2 unsigned long の : 122 : 123 : c hgvatr (char attr 124 : uns igned int xl, Turbo C Ver. 2.0 の conio. h の一部 List 6 / * secret bit / * NO secret bit / * blink bit / * No blink bit reverse bit NO reverse / * underline bit # define SECRET # define NOSECRET # define B い NK # define NOB い NK # define REVERSE # define NOREVERSE # define UNDER い NE 0X00 0X01 0X02 0X00 0X04 0X00 0X08 cboxprot. h List 7 1 : / * CM9 圓 8 * / 2 : 3 : # i fndef F I し E 4 : #include く stdio. h> 5 : #end i f 6 : #ifndef WINDOWH 7 : #include ” window. h ” 8 : #end i f 9 : #ifndef GMNSTRR 10 : #include ” menurd. h ” 11 : #endif 13 : menurd (char *fi lename, Char *cmd, char *arg) : 15 : 17 : bkdraw(char *noji) : 19 : keidraw(char *moji) : 20 : 21 : keydraw (char * 田 oj i) : 22 : 23 : seldraw (char *moj i, 24 : PILE *fp, Char *cmd char *arg5 26 : 28 : se lbar (struct Gmnstr mn ロ , 29 : Char color, 30 : Char rcolor, int ー inenum, 32 : int initl, 33 : int ura) : 34 : 35 : textkei2(int xl, int yl, int x2, 38 : int y2. 39 : char col, 109 応用 C 言語

5. 月刊 C MAGAZINE 1991年3月号

宣言の部分と , 繰り返しや分岐のところな どの制御構造の節目にコメントを入れます。 それて、は , List 6 を見てください。これは List 7 オーソドックスな main 関数の書き方 文字列操作の関数 ( コヒ。ーと比較 ) を説明し た方法て、 , コメントを入れて記述したもの て、す。実際には , List 6 はわかりきったアル こまて、詳しく書 ゴリズムの関数なのて、 , く必要はないのて、すが , コメントの入れ方 の例として見てください 1 : #include く stdio. h> 3 : nain() printf("This is the 5 : 2 : main 関数を int 型として定義する書き方 1 : #include く stdio. h> 2 : 3 : int main( void ) List 10 C Magaz ine. 5 : 6 : printf("This is the C Magazine. %n") : return 0 : main 関数を void 型として定義する書き方 1 : #include く stdio. h> 2 : 3 : void main( void ) List 8 5 : printf("This is the C Magazine. %n") : OS に値を返す main 関数の書き方 ( exit ) List 1 1 ex i t ( 0 ) : printf("This is the C Magazine. %n") : 4 : void main( VOid ) 2 : #include く stdlib. h> 1 : #include ctdio. h> 7 : 6 : 3 : OS に値を返す main 関数の書き方 ( return ) List 9 return 0 : printf("This is the C Magazine. %n"); 3 : main() 1 : #include く stdio. h 〉 6 : 5 : 2 : 126 C MAGAZINE 1991 3

6. 月刊 C MAGAZINE 1991年3月号

拡張 C として の C + + List 5 れず , クラス変数がグローバル ( 外部変数 ) てあればメンバ変数は 0 ( ゼロ ) に初期化され る。しかし , クラスを用いたプログラムて は , クラス変数を宣言したとき初期化を行 う特別な関数を呼び出すことて , メンバ変 数を初期化する手法がよく使われる。また , 初期化に対してクラス変数の有効範囲の終 了時点てクラス変数を消去し , 後始末を行 う特別な関数がある。これらの特別な関数 を , コンストラクタ ( 初期化を行う ) , ディ ストラクタ ( 消去を行う ) と呼ぶ。 コンストラクタ クラス変数を初期化する関数て , クラス 変数を宣言した場合や演算子 new によって領 域を確保した時点て , 自動的に呼び出され る。このコンストラクタは , クラス名と同 じ名前て、定義する。また , 関数はクラスの 公開部に記述する ( List 6 参照 ) 。 List 6 ては , コンストラクタがオーノヾーロ ードされており , リスト中の ( 3 ) のように初 期値を指定しないて変数の宣言を行ったよ うな場合は , ( 1 ) のコンストラクタが呼び出 される。また , 値が指定された場合 ( リスト 中の ( 4 ) ) は , 引数のあるコンストラクタ ( リ スト中の② ) が呼び出される。初期値の指 定は , リスト中の ( 4 ) の形式により , 定数や 変数 , 式を指定する。 コンストラクタの定義されているクラス は , 変数の宣言や演算子 new により領域カ巧寉 保されると必ず呼び出される。したがって , List 6 において , リスト中の ( 1 ) のコンスト ラクタが定義されていないとすると , ( 3 ) の クラス変数の宣言てエラーとなる。これは , 引数なしのコンストラクタが定義されてい ないためてある。 このコンストラクタの使用により , C 言語 の初心者がよく行う「初期化されていない変 数への演算」といった誤った処理 ( バグ ) を防 ぐことになる。また , List 6 には挙げていな いが , 外部変数として宣言されたクラス変 strcpy( name, a_name) ; a—age; age 20 : VO i d employee: :get(int& a_no, int& a-age) char* a name, 22 : no : a_no 23 : strcpy ( a_name, name) : 24 : age : a_age print ( ) 26 : VOid printf(:no = Xd, name = Xs, 28 : age 30 : class emp-l ist emplist[10] : employee* 32 : static int cnt; 33 : public: 34 : put ( emp loyee* ) : VO i d 35 : get( int ) : employee* 36 : pr i nt ( vo i d ) ; VO i d emp-l ist: :put( employee* p ) 38 : VO i d 39 : { emplist[ cnt ] 40 : 41 : cnt 十十 : 42 : } 43 : emp-list::get( int no ) employee* 44 : { for(int i 45 : 0 : i く cnt : i + + ) { if( emplist[i]->get-no ー 46 : return( emplis 48 : 49 : return ( emp loyee* ( の ) : emp-list::print() 51 : VOid for(int i 0 : i く cnt; i 十十 ) emplist[i]->print(); 54 : 56 : emp-list me i bO : 57 : main() 59 : int no, age, name [ 30 ] : 60 : Char int inp-emp(int&, char*, int&) : extern 62 : 63 : for (i = 0 : i く 10 ; i + + ) { if( ! inp_emp(no, 64 : name, age) ) break,• 66 : emp loyee* p = new emp loyee; 67 : p->put( no. name, age) : 68 : me i bO. put ( p ) : 69 : meibO. print(); printf("serch ・ no scanf("Xd ” enployee* p = meibO. get( no ) : p->print() : 76 : int inp_emp(int& no, char* name, int& age) printf("lnput NO scanf("Xd" i f ( no = return no : printf( ” name scanf("Xs ” name) : printf(" age scanf("%d" &age) : return no; = XdYn ” , no, name, no 拡張 C としての C 十十 89

7. 月刊 C MAGAZINE 1991年3月号

ライフホ、 lnformation from Compiler Makers Lattice C ンから受け取ったシフト JIS コード Q を , JIS コードに変換します。て、す List 1 のようなプログラムで , 正しく環境変数が設定されません。 から , シフト JIS の第 1 バイトにあ たる 0X81 ~ 0x9F , 0xC0—0xFE を どうしてですか ? 受け取ると , MS-DOS が変換しま A す。プリンタを細かく制御するた putenv 関数の引数を外部変数 めには MS ー DOS を通さずに , BIOS にするか static 変数にしてくださ ルーチンを使って , 直接データを い。変数 environ は , ポインタの配 出力する必要があります。ただし , 列を指すポインタて、すが , putenv プリンタに漢字コードを出力する 関数は , その配列に引数て、渡され た文字列へのポインタを追加して , ときには , アプリケーションて、シ 環境変数を変史しています。 フト JIS から JIS にコード変換する 必要があります。プリンタの仕様 関数の自動変数を putenv の引数 書をご確認ください に渡すと , 関数を抜けたときに envi ron に追加されたポインタの指す内 Q Lattice C には 16 ビット in, out 容がなくなってしまうために の関数がありませんが , どうすれ 指摘のような現象が起こります。 ばよいですか ? putenv の引数の内容がなくならな いように , 変数を宣言してくださ A Lattice C のパッケージ内に IO. ASM というファイルがありま す。これは , inp 関数と outp 関数の プリンタを制御するために , ソースプログラムて、す。これを修 fprintf 関数を使って第 1 引数に std 正して使用してください。 List 2 に prt を指定して出力していますが , 修正例をつけます。 プリンタのモードを変更しても効 アセンプル方法は , ファイル LC. かないことがあります。また , 0 MAC をカレントディレクトリにコ X81 ~ 0x9F , 0xE0 ~ 0xFC を出力す ヒ。ーするか , masm の / I オプション るとコードが化けます。どうすれ て、ファイル LC. MAC のあるディレ ばよいでしようか ? クトリを指定してください A また , メモリモデルに合わせて , stdprt は , MS—DOS の標準出 ファイル DOSx. MAC(x S,P,D, カルーチンを経山してプリンタに L) ( または S,P,D,L ディレクトリ内 データが出力されますが , MS - DOS のファイル DOS. MAC ) をファイル は改行後アプリケーションからの 名 DOS. MAC にして , カレントディ データを出力する前に , プリンタ レクトリにコヒ。ーするか , /I オプシ にモードを初期化するようにプリ ョンて、指定してくさだい。さらに , / ンタに制御コードを出しています。 Mx オプションを指定してくださ また , MS-DOS I•. の漢字コードは シフト JIS コードて、すが , たいてい 例 : masm /la:*lc /la: のプリンタのコードは JIS コードて、 *lc*s /Mx io; す。 MS-DOS は , アプリケーショ 152 C MAGAZINE 1991 3 putenv 関数サンプル List 1 char S[20]= ” SUBTEST=" switch(i){ case 1 : strcat(s,"R00T") : break: case 2 : strcat(), "sub つ : break; defaul t : strcat(), "OTHERS") : break: putenv(s) : 11122 % 囲四引 extern char **environ : VO i d sub ( i (t) : main() char **p, int i; printf( ” enter . scanf("Xd",&i); sub(i); for(p=environ;*p; p 十十 ) printf("XsYn". (p) : 1 ・つ 0 っ 0 -4 -0 ^ 0 ″ー 8 0 1 ・り 0 っ 0 4 -0 物 0 void sub(int i) 0 2. ASM List 2 PORT I/O FUNCTIONS TITLE SUBTT し C 叩 yright 1982 by し attice, c. NAME PORTIO INCLUDE DOS. MAC PSEG 、ーりなっ 0 4 LO ^ 0 ー 8 0 ・ 1 り 0 っ 0 -4 -0 7 ・ 8 0 14 り 0 っ 0 -4 LO CD ″ー 8 0 1 よ 00 っ 0 -4 ・に ^ 0 ″ー 8 0 、ー 00 っ 0 4 LD 、 1 、 1 1 よ、 1 1 よ、よ、ー、よ、 1 1 よっ 0 りなっ 0 っ 0 っ 0 っ 0 っ 0 っ 0 つなり 0 っ 0 っ 0 れ 0 っ 0 っ 0 っ 0 っ 0 っ 0 っ 0 っ 0 -4 ・ -4 -4 4 ・ 4 -4- i nput word fron port : name inpw(port) : : synopsis C int c; retur ned WO rd int port; port addres s : description This function inputs a word fron the specified port address and returns it as the function value. lnpw Q CBEGIN i 叩 w MOV DX, ARGS[O] Ⅷ AX,DX XOR AH, AH CEND lnpw PAGE : GET PORT A DDRESS ;GET INPUT wo 団 し EAR HIGH BYTE ←削除します - output word t0 port : name outpw : synopsis outpw(port, c) : int port; port address word to send description Thi s function sends the spec ified word to the specified port. CBEGIN outpw MOV DX, ARGS[O] MOV AX, ARGS[2] OUT DX, AX CEND outpw ENDPS END •,GET PORT ADDRESS ;GET OUTPUT WORD

8. 月刊 C MAGAZINE 1991年3月号

ニ : ロ はじめて学ぶプログラー ニンク 関数 facto 「 ial( sc 風のコーディングスタイル ) 関数 factoriaI(K&R 風のコーディングスタイル ) List 1 List 4 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : double factorial (int num) 6 : double fact_num 7 : i f (nun くの { 8 : " 正数を入力して下さい。 Yn" ) : fprintf (stderr, 9 : exit(l); } else if (num = 0 Ⅱ num = return 1. 0 : 13 : else { for ( : num > 1 : 14 : 15 : fact_nun num; 16 : 17 : return fact nun : 1 : #include く stdio. h> 2 : #include く stdlib. h 〉 3 : 4 : double factorial (int num) 6 : double fact num 7 : if (num く 0 ) 8 : 9 : fprintf(stderr, " 正数を入力して下さい。 Yn"); exit(l); else if (num return 1.0 : e ー se 20 : = 0 Ⅱ num = for ( : num > 1 : num--) fact_num * = num : return fact_num ; 関数 facto 「 ial( バーレンやプラケットの中にスペースを入れる ) 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : double factorial( int num ) 6 : double fact_nun 7 : if ( num く 0 ) { 8 : 9 : fprintf( stderr, " 正数を入力して下さい。 Yn" ) ; ex i t ( 1 ) : } else if ( num = 0 Ⅱ num = return 1.0 : else { for ( 14 : : num 〉 1 : num— 15 : fact_num * = return fact num; List 2 関数 factorial( sc 風の亜流のコーティングスタイル ) List 5 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : double factorial (int num) 6 : double fact_num 7 : if (num くの 8 : 9 : " 正数を入力して下さい。 Yn") : fprintf (stderr, exit(l); else if (num = return 1.0 : 14 : else for ( : nun > 1 : nun fact_num * = num; 20 : return fact_num : 関数 factorial(BSD 風のコーティングスタイル ) List 3 1 : #include く stdio. h> 2 : #include く stdlib. h 〉 3 : 4 : double factorial(int num) 6 : double fact_num 7 : 8 : if (num くの { 9 : fprintf (stderr, ”正数を入力して下さい。 Yn"); exit ( 1 ) : else if (num = return 1.0 : else { for ( : nun 〉 1 : num fact_num * = : return fact_num : 123 はじめて学ぶ C プログラミング

9. 月刊 C MAGAZINE 1991年3月号

List 2 0 retcode=FALSE : } 26 : main( int argc, char * argv ロ ) 23 : char chiIdarg[200] : / * 子プロセスへの引数 * / , 21 : void far pascal TermVi0Kbd( void ) ; void far pascal InitVi0Kbd( int nattr, int ・ 19 : / * 外部 D ししルーチンのプロトタイプ * / 、 17 : #define FA し SE 0 ー 16 : #define TRUE 1 ー 20 : ー 22 : 24 : ー 25 : ー 28 : 、 29 : : 30 : ー 31 : ー 32 : 、 33 : ー 34 : , 35 : ー 36 : ー 37 : ー 38 : 39 : ー 40 : ー 42 : 43 : 44 : ー 45 : ー 46 : ー 48 : ー 49 : 50 : 52 : 53 : ー 54 : 1 55 : 56 : ー 58 : 59 : ー 62 : ー 63 : 64 : ・ 65 : ー 66 : ー 67 : ー 69 : ー 73 : ー 74 : ー 76 : ー 77 : 82 : 84 : ー 87 : hattr Char RESULTCODES USHORT Char far * Char far * int SBL achFailNameC128] : rescResults : retcode childname : aptr : sel printf ("Yn OS / 2 Command Editor/Retriever 1.0 Yn") : puts(" Usage :de くコマント・フ・ロセッサノフルネーム > [ コマンドフ・ロセッサへノヒキスウ ] " ) : if ( argc く 2 ) { printf(" Copyright (c) 1989 by WiIIiam IvesYn"); / * 子の引数の配列を構築する * / chi ldname= (char far * ) argv [ i] return; *aptr=0; / * NU しし終端子をニ重に置く *aptr 十十 = e 1 se if ( retcode) { aptr 十十 : aptr 十 = strlen(argv Ci]) : strcpy( aptr, argv[i] ) : for ()i く argc;i + + ) { retcode=TRUE; i f ( a rgc > ( i + 1 ) ) { aptr (char far * ) chi ldarg / * 自作の kbdstringin ルーチンを登録する * / InitVioKbd( 0X17 , 0X7 ) : / * V i 0 & Kbd のステートをセープする * / if( retcode ) { retcode = KbdRegister((PSZ)"dedll", (PSZ)"-INPUTSTRING", (ULONG)KR_KBDSTRINGIN ) を return : printf(" 新たな KbdStringIn を登録できません :RET = XdYn",retcode); printf(" 工ラー Xd : コマント・フ・ロセッサの実行中 . Yn", retcode) : if ( retcode ) { (PSZ)chiIdarg, NU しし , &rescResuIts, childnane) : retcode DosExecPgm( achFai IName, sizeof(achFailName), EXEC_SYNC, e 1 se NUL し , NUL し , &rescResuIts, childname) : retcode DosExecPgm( achFaiIName, sizeof(achFailName), EXEC_SYNC, if ( argc ← 2 ) / * コマント・フ・ロセッサをスホ・一ンする * / puts(" Usage :de くコマント・フ・ロセッサノフルネーム > [ コマント・フ・ロセッサへノヒキスウ ] " ) : / * ⅵ 0 & kbd のステートをリストアする * / TermV i 0Kbd ( ) : / * kbd str i ng i n ルーチンをインストールから外す * / KbdDeRegister() : 89 : } / * ma i n ( ) * / の試作品て、は , キーストロークをバックグ ラウンドプロセスの中て、原始デバイスレベ ルて、捕捉しました。第二の試作品て、は , フ ォアグラウンドプロセスがシェルを隔離し て , パイプを介してその画面とキーポード を管理しました。キーポードからのコマン ド入力が必要なときに , シェルがユーザ定 義のコードをコールて、きる方法があるなら , CLR はもっと簡単に書けるて、しよう。 OS/2 はそのアプリケーションズプログラ ムインタフェイス (API) に , 多様なサービス を提供しています。これらのサービスは , を比較的楽に書ける , といっておくだけて、 すが , OS / 2 の SDK を使えば , ューザは DLL 書き方の詳細は , 本稿の範囲を超えていま なければならない という点て、す。 DLL の ーの決まりは , その代役サービスが DLL て、 KbdStringIn の代役を登録するだけて、す。唯 KbdRegister というサービスを使って うになります。そのために必要なことは , キーを使って文字列をエディットて、きるよ によって , ューザが OS / 2 のエディティング の中て、は ,KbdStringIn という名のサービス 置き換える能力を提供しています。 Kbd API 部をユーザ定義のサービスて、 ( ランタイムに ) れらの API はいずれも , 内部のサービスの一 実際はそれほど凄くはないのて、すが , 動作するはずて、す。 るアプリケーションは依然として , 正しく れと置き換えても , そのサービスを使用す は , ユーザが自作の DLL を書いて標準のそ のことを実現しているのて、す。ということ ラリ (DLL) として実装することによって , ます。それらをダイナミックリンクライプ が必要なときに , 必要に応じてロードされ ージのそれぞれ ( Dos 以外 ) が , そのサービス ービスが入っています。これらの AP レヾッケ ーボ、一ド , ビデオおよびマウスのためのサ ます。 Kbd, Vio および Mou API には , キ 般的なサービスは , DosAPI の中て、扱われ ます。ファイル I/O やプロセス管理などの一 い・くつかのグループに分類することがて、き Command-Line Retriever for OS / 2 31

10. 月刊 C MAGAZINE 1991年3月号

ホ - ランドジャ / ウ lnformation from C0mpiIer Makers Q BGI の outtext で漢字を出力し た場合の速度が遅いようですが , なぜですか ? A Turbo CVer. 2.0 て、は , 漢字 文字列をグラフィックス画面に出 力する場合に KCG アクセスモード をドットアクセスに変史していま こうすることて、フォントの 読み込み速度は向 E しますが , ド ットアクセスモードて、はテキスト VRAM E に漢字を表示て、きないた め , テキスト VRAM に漢字が表示 されているとちらついてしまいま す。このため , Turbo C 十十て、は KCG アクセスモードを変史してい ません。漢字文字列の描画速度を List 1 0 : text [ i] : fO 「 ( i buf [ 2 ] pc98crt(0xIb, kcg) : kcg int i, kcg; char buf[3] : void eouttext (char *text) 2 : #include く jctype. h> 1 : #include く graphics. h> 向 I•. させるためには , pc98crt 関数 を使って一時的に KCG アクセスモ ードを変史します (pc98crt(0x1b, 1 ) ; ) 。 ANK 文字列の出力と併用 する場合は , List 1 のプログラムを 組み込み , outtext を eouttext に置 き換えてください Q nntf("%d,%d*n" ー 32768 , ー 32768 ) ; とすると , ーっめは正し く一 32768 と表示されますが , ニつ めは一 1 が表示されてしまいます。 A ー 32768 という値は , long 型の 定数として評価されます。 % d は int 型のための書式指定子 て、すから正しく表示て、きなくなる わけて、す。ー 32768 が long 型として 3 : 4 : 6 : 7 : 8 : 9 : 12 : 14 : 15 : 20 : 22 : 23 : 24 : 25 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : if (iskanji ((unsigned char)text[i])) if (kcg) pc98crt(0xlb, kcg = の : buf[l] buf[0] = text [i] : } else { outtext (buf) : = の pc98crt(0xlb, if (kcg buf[l] bufC0] = text[i] : kcg outtext (buf) : 28 : void eouttextxy(int x. int y, int sx, sy, sx = getx ( ) : = gety ( ) : SY noveto(), y) : eouttext (text) : moveto(sx, (y) : if (kcg) pc98crt(OxIb, の : 150 C MAGAZINE 1991 3 char *text) 評価されるのは , これが、、〃 いうトークンと 32768 という二つの トークンからなる表現て、 , 32768 が ( 符号っきの ) int 型て、収まらないた と A ることがあります。 た後 , 浮動小数演算ができなくな を呼び出すと , 親プロセスに戻っ spawn 関数などで子プロセス Q てください きに (unsigned char) て、キャストし て、宣言するか , 引数として渡すと まいます。変数を unsigned char 型 め , 上位バイトが 0xFF になってし の値として拡張されます。このた のとき 0X80 以上の文字コードは負 自動的に int 型に昇格しますが , 引数として char 型が渡されると , イプ宣言がされていないか可変個 号っきとなっています。プロトタ char 型は , デフォルトて、は符 printf("%02X%n", c); Char c; されてしまいます。 のですが , 先頭に余計な FF が付加 数の文字コードを表示させている printf の %02X 指定で , char 変 Q 警告を発生させることがて、きます。 L がついていない定数表現に対して て、 , long 型のためのサフィックス ックスをチェック (X) すること ity て、 Constant is long チェックポ Compiler ー Messages ー Portabil て、 , 統合環境版て、は Options ー ー wcln ( または一 w ) を指定すること コマンドラインコンパイラて、は long 型となるためて、す。 めに long 型となり , 全体としても Turbo C 十十 A 浮動小数演算は , 割り込みべ クタ INT 3xH を介して行われま す。これらのべクタはスタートア ップルーチンて、設定されますが , 發プロセスて、これらのべクタの内 容が破壊されるとその後の計算が 正しく行われません。この場合は , 發プロセスの実行後に fpreset 関 数を呼び出すことて、 , これらのべ クタを再設定することがて、きます。 Q プログラムの実行中に一 キーを押すと , いくつかのべクタ が復帰されないまま終了してしま います。 A Turbo C 十十のスタートアッ プルーチンは , いくつかのべクタ を書き換えており , これは終了ル ーチンて、もとのアドレスに復帰さ れます。プログラムの実行が て、中断されると , これらのべクタ が復帰されないままプログラムが 終「してしまいます。この場合は ctrlbrk 関数を使って , コントロー ルプレークの割り込みハンドラを 指定することて、対応て、きます 0List 2 を参照してください Q 環境版を使っていますが , コ ンパイル中ディスクへのアクセス が行われたまま , 戻ってこなくな るようなのですが , ハングアップ してしまったのでしようか ? A Turbo C 十十て、は , 使用可能 メモリが少なくてもコンパイルて、 きるようにハードディスクとのメ モリスワップが行われます。拡張 メモリ (EMS メモリやプロテクトモ ード用のメモリ ) がない場合は , ハ ードディスクとのメモリスワップ