三ロ はじめて学ぶプロクラミンク List 1 て、は w すなわち write モードて、ファ イルをオープンしていました。ファイルオ ープン時に , そのファイルは書き込み専用 て、ある , と指定をしておいたわけて、す。 の指定を行うのが fopen 関数の第 2 引数て、 す。この引数の取り得る値を TabIe 2 に示し ました 0Table 2 ー 1 がファイルのオープンモ ードを表しています。この指定によってフ アイルは読み , 書き , 追加 , 読み出し / 更 新 , 書き込み / 更新 , 追加 / 更新の指定がて、 きます。これに加えて TabIe 2 ー 2 の文字を付 加することにより , テキストモード , バイ ナリモードの指定がて、きます。 さて , List 2 を実行してみてください のプログラムては read モード <abcde. xyz と いうファイルをオープンしています。 read モードはそのファイルがすて、に存在するこ とを前提にしています。しかし , このファ イルは用意してありません。ところが List 2 のプログラムを実行しても , ファイルのオ ープンは失敗しているはずなのにとくに工 ラーがて、るとか , 変わったことはなにも起 こりません。逆にいえばファイルオープン 時のエラー管理は自分自身て、行わなければ ならないわけて、す。 fopen 関数て、はファイル のオープンに失敗した場合 , NULL が返っ てくることになっていますのて、 , これを利 用したエラー管理の例を List 3 に示します。 fopen て、オープンされたファイルに対して 実際に入出力を行うためには , getc, fgetc, fgets, putc, fputc, fputs, fscanf, fprintf などといった関数 ( マクロ ) を用います。 れらの関数は以前にててきた , getchar, putchar, gets, puts, scanf, printf とほぼ同じ働きをします。 scanf , P ⅱ ntf など はすて、にオープンされている , 標準テキス トストリーム (Table 3 参照 ) に対して読み書 きを行っていました。それに対し fscanf, fp 「 intf といった今回説明する関数などは , ユ ーザがオープンしたファイルに対して入出 はじめて学ぶ C プログラミング 135 ・形式 int fscanf()l LE * stream, const char * format, argl, arg2, ・機能 ファイルから文字列を入力し , 入力書式制御にしたがって変換し , 変数に値を格納する 関数名 printf ・形式 int printf(const char *format, argl, arg2, ・機能 指定された変換仕様にしたがって各引数の値を標準出力へ文字列として出力する 関数名 fp 「 intf ・形式 int fprintf(FlLE *stream, const char *format, a 「 91 , a 「 92 , ・機能 指定された変換仕様にしたがって各引数の値を文字列に変換しそれをファイルに出力する 5 プロック入出力 関数名 fread ・形式 sizet fread(void * ptr, size t size, size t n, FILE * stream) , ・機能 入力ストリームからプロックでテータを読み込む。プロックの形式は , 大きさ size の要素が n 個 からなる 関数名 fw 「 ite ・形式 size t fwrite(const VOid * ptr, size t size, size t n, FILE * stream) , ・機能 大きさ size の要素が n 個からなるプロックテータをストリームに書き込む 6 ファイル位置設定 関数名 fsee k ・形式 int fseek(FILE *stream, long Offset, int origin) , 0 「 igin の位置から 0 幵 set で指定されたバイト数だけファイル位置を移動する ・機能 関数名 ftell ・形式 long ftelI(FlLE *stream) , ・機能 ファイルの現在位置を調べる 関数名 rew ・ ind ・形式 VOid rewind(FILE * stream) , ファイルの位置をそのファイルの先頭に移動する ・機能 関数名 fgetpos ・形式 int fgetpos(FILE * stream, fpos t * pos) , ファイルの位置を得て変数に格納する。この関数はれ関数を用いて実現できる ・機能 関数名 fsetpos ・形式 int fsetpos(FILE * stream, const fpos t * pos) , ・機能 指定された位置にファイルの位置を移動する。この関数は fseek 関数を用いて実現できる 7 ファイルの状態を表す マクロ名 feof 匚 , ーロ
標準入力から文字列 ( ファイルの終わりの前 , または \ n の前まで ) を読み込み , 格納する ③についてもう少し説明しましよう。ど のストリームと結合したかは戻り値として 得られます。具体的には , ストリームを制 御する変数へのポインタが返ってきます。 ただし , ファイルのオープンに失敗したら マクロ名 getchar ・機能指定されたファイルから 1 文字読み込むマクロ NULL が返ってきます。 具体例を挙げましよう (List 1 ) 。この例て、 ルをクローズする関数が fclose 関数て、す。 する変数へのポインタ ) を受け取り , ファイ という情報 ( クローズするストリームを制御 また , 「どのストリームをクローズするか」 は , これは , たとえば構造体として次のように いう変数は日 LE 型として宣言されています。 て f ⅱ el という変数に代入しています。 f ⅱ el と トリームを制御する変数へのポインタ ) を得 ムと結合しているかという情報 ( すなわちス オープンしています。そしてどのストリー w(write) モードで , myf ⅱ e. xyz という名のファイルを ・形式 ・機能 関数名 ・形式 ・機能 関数名 ・形式 ・機能 関数名 ・形式 ・機能 関数名 ・形式 ・機能 int getchar(void) , 標準入力から 1 文字読み込むマクロ。 getc(stdin) と同じ char * gets(char *Str) , gets int fgetc(FILE * stream) , fgetc getc とまったく同じ働きをする。こちらはマクロでなく実際の関数呼び出し fgets ( ¥ N は格納されない ) み出す ) 際には , 押し戻されたのと逆順に返される 文字 c を unsigned cha 「に変換し , 入力ストリームに押し戻す (push-back)o 再び取り出す ( 読 int ungetc(int c, FILE *stream) , ungetc 入力ファイルから , 長さ max ⅱ ne 未満の文字を読み込み , 格納する ( ¥ N も格納される ) char *fgets(char *Str, int maxline, FILE *stream) , 定義されています。 typedef struct unsigned unsigned unsigned signed signed signed unsigned unsigned signed } FILE ; Char Char int int Char Char int int *fpi : *bptr ; flags ; blevel• bsize ; fd ; ho ; istemp token ; 3 ファイルへの出力 マクロ名 putc ・形式 int putc(int c, FILE *stream) , ・機能指定されたファイルに 1 文字書き込むマクロ マクロ名 putchar ・形式 ・機能 関数名 ・形式 ・機能 関数名 ・形式 ・機能 関数名 ・形式 ・機能 int putchar(int c) , 標準出力に 1 文字書き込むマクロ。 putc((c), stdout) と同じ fputc int fputc(int c, FILE * st 「 eam) , putc とまったく同じ働きをする関数 putS int puts(const char * str) , 標準出力に文字列を書き込む。その際出力に改行文字を付け加える 出力ファイルに文字列を書き込む int fputs(const char * str, FILE * st 「 eam) , fputs これについては必ずしも構造体て、定義さ れているとは限らず , またメンバの数や機 能についてもこのとおりとは限りません。 イメージとして捉えてください。それて、も , ファイルの上て、の位置 , ファイルの状態 , バッフアの状態を表す情報をまとめて FILE 型という変数型が定義されています。そし てこの日 LE 型こそがストリームを制御する 134 CMAGAZINE 19 10 要な情報て、ある , モードについて話しまし さて , ファイルをオープンするときに必 変数の型となっているわけて、す。 ために必要なすべての情報を記録している 4 書式つき入出力 関数名 ・形式 ・機能 関数名 scanf int scanf(const char * format, argl, arg2, 標準入力からの文字列を入力書式制御にしたがって変換し , 変数に値を格納する fscanf
のて、 , その実行結果は一一の出力に よる BEEP 音が鳴ってから、、 8 クが表示され ることになります。 五ロ 識別子 数字 文字列 文字定数 句読点 演算子 語句 変数宣言について 変数宣言における型指定子 , 型修飾子 , 記憶クラス指定子などは , どのような順番 て、現れても許されます。以下に挙げる 3 つの 例は , どれも同じ静的変数 A を宣言していま す ( ただし , int と sho 「 tint が同じて、あった場 cn N 2 0 識別子 2 A . static int A ; static signed short int A ; int short signed static A ; ただし , 以下のような宣言は許されませ 1 0 進整数 数字 8 進整数 1 6 進整数 浮動小数点数 ん。 int shO 「 t signed SO 「 t A ; short unsigned long int A ; これらは , 型指定子が重複して使用され ているためて、す。 1 0 進整数 整数接尾子 0 . 整数接尾子 8 進整数 7 0 . 0 1 6 進整数 整数接尾子 9 0 0 配列宣言 / 初期化 ANSI て、は , 以下のような配列宣言 / 初期 化を行うことが可能て、す。 cha 「 cc [ ]="ABC" これは , 文字列定数と文字定数のリスト が , 文法規則上においてほば同一のものと してあっかわれているためて、す。これを通 常の ( 見なれた ) 形式に書き換えると以下の ようになります。 整数接尾子 1 0 . 9 0 . 浮動小数点数 指数 浮動小数接尾子 指数 0 . 十 9 char cc [ ] プロジェクト PragmaC 51
引 mo の場合にはアドレス値として考えると , + 十 sizeof(a) を評価してみるとよい ( たとえば , ポインタを baz に渡しているにすぎないのて、 p が必ずしも 1 増やしているとは限らない sizeof(a)) : とする ) 。 ある。 printf("%d%n" とに注意されたい そのため baz の側て、 , たとえどんなに配列 sizeof(int*) と同じ値が返されるはずて、あ る。したがって , List 5 および List 5 ' の引数 が一括して渡されてくるかのように記述し 配列形式の宣言 ても , それは意味をなさず , たんに先頭要 宣言は次の形式とまったく同じて、ある ( List さて , 話をややこしくしている問題のふ 素へのポインタが渡されてくるにすぎない 7 参照 ) 。 たつめを考察しよう。それは関数の仮引数 先の baz の引数宣言は , いかにも配列の宣言 これならば , a がポインタて、あることが一 に対する配列形式の宣言て、ある。次の関数 て、あるかのように見えるのだが , 実はたん 目瞭然て、あろう。その場合て、も , 関数 baz の を見てもらいたい (List 5 参照 ) 。 本体て、は a 国と書いてもかまわないというこ なるポインタて、しかないのて、ある。 まず , C て、は配列をそのまま一括して関数 ・関数の仮引数として配列風に宣言して とは最初に述べた。 へ引数て、値渡して、きないということを思い も , 実際にはポインタとして取り扱わ なお , List 5 ' の引数における int a ロと 出してほしい ( 配列を構造体て、包んて、しまえ いった宣言の形式と , 次のような外部リン れる。 ば可能だが・・・・・・ ) 。この baz 関数は , 別なと List 5 は次のように仮引数の配列サイズを ケージをもっ配列の宣言とを混同してはな ころから , List 6 のように呼び出すことにな 省略することがて、きるが , これて、もまった らない (List 8 参照 ) 。 List 8 の a は正真正銘の配列て、ある。これ るのだろう。 く事情は同じて、ある。すなわち , List 5 にお 関数への実引数は式 ( 厳密には「代入式」 ) を extern int * a : と書くと , まったく違う ける a [ N ] の N はほとんど意味はない ( List 5 ' て、ある。したがって , data という配列名が 意味になり , プログラムは正常に動作しな 参照 , なお , 2 次元以上の配列を受け渡す場 己されていれば , それは「配列名は先頭要素 いて、あろう。 合などはサイズの指定が重要になる。それ へのポインタに自動変換される」というルー については回をあらためて述べたい ) 。 ルに従って処理される。 zot の中て、の baz の いずれにせよ , 引数 a は配列て、はない。そ 呼び出しは , 実際には data の先頭要素への れはポインタなのて、ある。 baz の内側て、 1 ロ List ニ baz (data) : total ー 8 100 #define N baz(int a[N]) long 11 「と 4 ・ -. 0 ^. 0 ー 8 0 ) 0 1 ↓ LiSt long i nt i : sum 十十 i ) for (i ニ 0 ; i く N; S u m return sum : baz(int *a) 11 ワ】っ 0 -44 LO 《 0 ー 8 long long i nt i : sum for ( i 0 : i く N : 十 + i ) sum return sum : LiSt baz(int long List extern int a[]; long baz(void) 11 ワ 3 っ 0 ・ L.n れ 0 0 ー 8 0 1 よ List long i nt i : int data CN] : void zot(void) 1 人っなっ・戸 0 ^ 0 sum for ( i ニ 0 : i く N : + + i ) sum sum : return total; long ANSI C : more 121
TabIe 3 ファイル八ンドルのニ重化 DOS ファンクション 45h ファイル八ンドルのニ重化 引数 AH=45h BX = ファイル八ンドル ー NT 21 h 返り値キャリー = 1 ファイル八ンドルの複製 TabIe 5 dup 関数 される を読み書きしても , 両方のファイル八ンドルのファイルポインタが更新 ル八ンドルを AX レジスタに返す。どちらのファイル八ンドルでファイル 機能 BX レジスタで指定されたファイル八ンドルをニ重化して , 新規のファイ AX = 新規のファイル八ンドル キャリー = 0 = 06h : 無効な八ンドル AX=04h : オープンされているファイルが多すきる 0 プログラマのための ' れる。このファンクションはファンクション 45h とともに使用して標準 ル八ンドルがすでにオープンされている場合 , コピーの前にクローズさ 指定された新規のファイル八ンドルにコピーする。 CX レジスタのファイ 機能 BX レジスタで指定されたファイル八ンドルをニ重化して CX レジスタで キャリー = 0 : 正常終了 = 06h : 無効な処理 AX=04h : オープンされているファイルが多すきる 返り値キャリー INT 21h CX = 新規のファイル八ンドル BX = 既存のファイル八ンドル 引数 AH=46h DOS ファンクション 46h 指定したファイル八ンドルへのコピー TabIe 4 指定したファイル八ンドルへのコピー TabIe 7 割り当てずみのファイル八ンドル 出力のリダイレクトに使用されることが多い int dup(handle) : int handle オープンずみのファイルノ、ンドル 返り値 > = 0 : 新しいファイル八ンドル ー 1 : 工ラー TabIe 6 dup2 関数 ファイル八ンドルの複製 int dup2 (oldhandle, newhandle) : int oldhandle : int newhandle : オープンずみのファイル八ンドル 新しいファイル八ンドル ファイル 八ンドル 0 1 2 3 4 役割 標準入力 標準出力 標準工ラー出力 補助入出力 プリンタ出力 テパイス名 CON CON CON AUX PRN stdprn C の相当する ファイルポインタ stdin stdout stderr stdaux 返り値 = = 0 : 正常終了 ー 1 : 工ラー バイプ パイプ機能もリダイレクトの仲間てす。 DIR ー SORT とするとディレクトリの結果がソートされ て表示されます。これは , DIR の標準出力→ SORT の標準入力 という接続を行っている結果てす。 リダイレクト機能は上記の入力のリダイ レクト , 出力のリダイレクトおよびパイプ 機能単体または組み合わせの総称て、す。 (TabIe 1 ) 。 という 3 つの部分から構成されています COMMAND.COM MSDOS. SYS ℃ . SYS MS-DOS は基本的に , やってるの ? リタイレクトは誰か 注 ) ファイルポインタから f ⅱ eno ( stdin ) でファイル八ンドルが取り出せる IO. SYS はデバイスドライバそのものて す。 CON, AUX, CLOCK などのキャラク タデバイスとドライプ A : , B : などのプロ ックデバイスからなります。 MSDOS. SYS は MS-DOS の本体て, シス テムファンクションの INT 20h ~ 3Fh て、呼び 出します。おなじみの DOS ファンクション Fig. 4 標準出力のリダイレクト ファイル八ンドル 1 ファイル八ンドル 1 の INT 21h の機能は MSDOS. SYS の機能て、 す。 COMMAND.COM は COPY, TYPE, DEL などの内部コマンドやバッチファイル を起動します。 それて、はリダイレクトやパイプの機能は この 3 つのうちどの段階て行われているのぞ ファイル八ンドル 1 を ファイルにリダイレクト ファイル 新 MS-DOS プログラミング入門 95
ControIIine ーンの数 ) , そして black と white の色 ( これ らを境界色および背景色として使うが , と くに黒と白て、なくてもよい ) が決ったら , ウ インドウを作ることがて、きます。ウインド ウを作るもっとやさしい方法はほかにもあ りますが , 本稿の方法だと , ウインドウか ら確実にカラーにアクセスて、きます。 ソースコードの main ( ) 関数の中て、は , / * ウインドウを作り ICCCM の値 をセットする * / SetUpWindow( display, visual, depth, colormap, black, white, &window ) : I C C C M は , I n t e r ー C 1 i e n t C 0 m municaitons Conventions Manual ( クラ イアント間通信規約マニュアル ) の頭文字て、 す。この文書は , X のアプリケーションの正 こて、は単純 しい動作を規定しています。 化のため , ICCCM のすべての値は設定して いませんが , ほとんどの場合はこれて、十分 て、 , window manager からの苦情はてない と思います。 SetUpWindow( ) 関数は , 私たち用のウィ ンドウを作ります。最初に , ウインドウの サイズと位置を決めます。 X て、は , 通常 , geometry specification と呼ばれるコマンド 行バラメータを渡します。 -geometry widthXheight 十 x 十 y これて , ウインドウの位置とサイズを指 定します (width, height,x,y は数値て、 ,width の後にスペースはない ) 。 X のプログラムの ほとんどが , この方法によってアプリケー ションのウインドウの位置を決めます。 次は , XSetWindowAttributes 構造体の一 部に値を入れます 0XGetVisuallnfo( ) 関数の 場合のように , 構造体の一部に値を入れて から , どの部分に値を入れたかをビットマ スクて XIib のルーチンに教えます。 XSetWindowAttributes 構造体の完全な姿 を , List 8 に示します。そのほとんどのフィ ールドに , 私たちは List 9 に示すデフォルト の値を使います。 event mask フィールドは , 私たちが ButtonPress イベント ( ューザがウインドウ 25 : i f ( 32 CM AGAZIN E 19 10 List 8 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 14 : 17 : List 9 1 : 2 : 3 : 4 : 6 : 7 : 8 : 9 : typedef struct{ XSetW indowAttr i butes : Cursor cursor; Colormap colormap; B00 ー override_redirect; long do_not_propagate_mask; long event-mask; B00 1 save_under : / * リクエストするだけ * / unsigned long backing_pixel; unsigned long backing_planes; int backing-store; / * リクエストするだけ * / int win_gravity; int bit_gravity; unsigned long border_pixel; Pixmap border-pixmap; unsigned long background-pixel : Pixmap background_pixmap; attribute_mask = CWBackPixel ー CWBorderPixel ー CWEventMask ー CWCoIormap; colormap; attributes. colormap attributes. event_mask ExposureMask ー ButtonPressMask; attributes. border-pixel fore : /*"black" の色 */ 5 : attributes. background-pixel = back; /*"white" の色 */ XSetWindowAttributes attributes; unsigned long attribute-mask; unsigned long back, fore; Colormap colormap; List 1 0 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 12 : 13 : 15 : 16 : 20 : 22 : 23 : 24 : 26 : 1 : DispIay *display; int screen; W indow parent : i nt x, y : unsigned int width, unsigned int border int depth; unsigned int class; v i sua 1 *V i sua 1 : height; ⅵ dth : / * 32 , 圓 0 以内 * / / * カラー・プレーンの数 * / / * われわれが探素したもの * / unsigned long attribute-mask; 11 : XSetWindowAttributes attributes : = DefaultScreen( display ) : screen = R00tWindow( display, screen ) : parent 14 : border_width / * 幅 2 ピクセル * / class InputOutput; / * または Input0nly, XCreateWindow( display, W indow または CopyFromPärent*/ window / * 、エラ parent, x, Y, width, height, border_width; depth, class, (Window)None ) { &attributes ) : attribute_mask, v i sua l, / * われわれの v i sua は /
また , 配列のサイズを指定することによ り , 次のような 2 タイプの初期化を行うこと もて、きます。 char cc [ 4 ] ー "ABC" char cc [ 3 ] ー "ABC 上記のふたつの例て、は , 初期化リストの サイズが同一て、あるにもかかわらず , 配列 のサイズ指定が異なっていますが , どちら の場合にも正常にコンパイルが行われます。 配列サイズとして 4 を指定したものは , 配列 サイズを省略した場合と同じ結果となりま すが , 配列サイズ 3 を指定したものは , 以下 のような宣言と等しくなります。 浮動小数接尾子 文字 文字ェスケーフ。 8 進工スケーフ。 1 6 進工スクーフ。 文字列 文字 文字工スケープ 8 進整数 8 進工スケープ char cc [ 3 ] つまり , 文字定数の末尾に存在するはず の \ O 〃は無視されるわけて、す。 型変換 1 6 進整数 1 6 進工スケープ 文字 文字ェスケーフ。 8 進工スケーフ。 1 6 進工スケーフ。 文字定数 式の評価が行われる際の比較的多くの場 合において , char 型から int 型への暗黙的な 拡張変換が行われます。この変換規則を C 言 語のプログラム風にまとめると以下のよう になります。 代入演算子 算術演算子 演算子 代入演算子 if(C = SignedChar) (signed int)C; else if(sizeof(C)== sizeof(unsigned int) (unsigned int)C ; else くく 52 CMAGAZINE 19 10
イルポインタやアクセスモードを変えるこ とにより , 互いに干渉し合うことがて、きま す。 第 2 の注意点が , ファイルアクセスがノヾッ ファリングされる場合・・・・・・ C 言語の stdio のラ イプラリを使用する場合・・・・・・に関して存在 します。 stdio を使ってデータをファイル に書き込むとき , データはバッフアが満杯 になるまて、 , またはバッフアをフラッシュ する関数がコールされるまて、 , あるいはフ めた一般名て、す。 exec 関数の原型は execve としての , プログラム名とそれに渡す引数 ァイルがクローズされるまて、 , メモリ上に て、 , これは int execve(char *path, char * を必要とします。しかしこのデータをユー argv [ ] , char *envp [ ] ) ; という引数形 バッファリングされます。このときはシス ザ入力やファイルから取得するときは , そ 式て、コールされます。 path は実行するプロ れは通常は単一の文字列て、あり , したがっ テムコールの w 「 ite 力すコールされて , ノヾッフ アの内容をファイルに書き出します。しか グラムのパス名 ( ファイル名の前に所在ディ て配列またはリストへとトークン化されな し , バッフアはプロセスの一部なのて、 , プ レクトリ名などのパス名をつけたもの ) て ければなりません。 List 4 に , execs 関数と ロセスの複製時にはそれも複製されていま す。 argv ( 引数の配列 ) は , この新たなプロ いう新しい exec 関数を示しますが , これは コマンドを文字列形式て、受け取るものて、す。 す。 fo 「 k がコールされたときに , バッフア内 グラムに渡す引数の文字列の配列て、す。 envp に書き込み用データがあると , このことに ( 環境ポインタ ) は , name=value という形 execs 関数の環境版 execse と , パス名版 よって予期せざる結果が生ずることがあり 式の文字列の配列て、す ( 例 : TERM = execsp は , 次のようになるて、しよう。 VTIO の。環境には通常 , ユーザのホームデ ます。 int execs(cha 「 *cmdlin) ; / * 原型 * / List 2 て、は , もとのプロセスが fputs をコ ィレクトリ , 端末のタイプなどの情報が入 ールして , 1 行のテキストをファイルに書き っています。 argv と envp はともに , NULL int execse(char *cmdlin, char *envp [ ] ) ; 込んて、います。 fo 「 k をコールした後て、 , 子と ポインタて、終わっていなければなりません。 / * 環境版 * / 親の両方がファイルをクローズして , 両方 exec システムコールのそのほかの 5 つのタ のプロセスのバッフアの中身をフラッシュ イプは , 基本的には execve と同じて、すが , int execsp(char *cmdlin) ; / * パス名版 * / しています。その結果 , データはファイル 引数の形式がやや違います。 List 3 が , その execs 関数は文字列 cmdlin をトークン化し 完全な一覧表て、す。これらの関数は , 引数 に二度書き込まれます。 て引数の配列を作り , それを使って execv 関 を a 「 gv て、渡すか , argO, argl , argn, プセスの変容 数のどれかをコールします。トークン化は , NULL というリストて、渡すかという 2 グルー cmdtok 関数をコールして行います ( ソース プにわかれます。関数名はそれを反映して をお見せしていません ) 。 cmdtok 関数は , 一般的にプロセスは , 新たなプログラム いて , v がっくのが配列 (vector) 渡しの関 ANSIC の st 「 tok 関数と似ていますが , トー 数 , ーがっくのがリスト渡しの関数て、す。 を実行するために生成されます。システム クン間の連続するホワイトスペースを 1 個の コール exec は , 新たなプログラムを起動し p て、終わる関数は , ファイル名を引数に取 および て , それを exec へのコールを実行したプロ スペースとして扱い , \ , ります。ほかはパス名を必要とします。 p て、 、、 # 〃というメタキャラクタを認識します。 グラムと置換します。その新たなプログラ 終わる関数は , コール側プロセスの環境内 これらのメタキャラクタの機能は , シェル に定義されているパス ( たとえはア ATH = : / ムは , 最初から実行されます。コールした の場合と同じて、す [ 参考文献 1 ] 。 bin:/usr/bin のようなパス ) を探索して , プログラムが新たなプログラムて、置換され execs 関数を使う代わりに , 既存の exec 関 るのて , exec のコールは成功するとリター ファイルを見つけます。 ンしません。通常は ( ただし必ずて、はなく ) , e て、終わる関数は , 新たな環境を渡せま 数のどれかて、シェルを起動して , それにト ークン化をさせることもてきます。実行さ fork コールの直後に exec がコールされま す。ほかは , 現在の環境を新たなプログラ れるコマンド行の入っている文字列が , シ ムへコヒ。ーします。 す。 exec 関数は , 6 つのシステムコールをまと 6 つの exec 関数はすべて , 個々のトークン ェルへの引数として渡されます。 List int execl (path, argO, argl, 1 : int execle(path, argO, argl, 2 : int execlp(file, 3 : argO, argl, 4 : int execv(path, argv) 5 : int execve(path, argv, envp) 6 : int execvp(file, argv) char *path, *file, *argn, *argv ロ , *envp[] : NU しし ) argn, NUL し envp) argn, NULL) argn, UN Ⅸの spawn よ , われを助けたまえ / 39
特集 0 十十とオプジェクト指向 Fig .1 ( b ) コンバイル速度 Fig. l(a) コンバイル速度 秒 ロ whet. c int. C SPlro. C 0 8 1 イ 5 、 4- へ 0 つ」 mystr. c getchar. c lOWiO. C maze. C printf.c Sleve. C str. c dhry. c 0 printf. c mallcc. c dhry. c ロ TC V. 2.0 ロ TC 十十 V 」 .0 mystr. C getchar. C ⅷ 0. c whet. c Sleve. C mallcc. c Str. C i nt. C maze. C SPlro. C ・・・ TC 十十Ⅵ .0 TC V2.0 Fig .2 ( b ) 実行時間 Fig. 2(a) 実行時間 whet SPlro int ^ 0 4- つな 60 50 getcha r mystr 40 30 lOWiO maze 20 pri ntr Sleve 0 str dhry m 訓 dhry ロ TC V2.0 ーコ TC 十十Ⅵ .0 mystr pri ntf getcha r SleVe whet mallcc ・ TC 十十Ⅵ .0 int str lOWi 0 SPlro maze TC V2.0 Fig .3 ( b ) ファイルサイズ Fig. 3(a) ファイルサイズ 単位・千 30 whet. exe 30000 SPlro. exe int. exe 25 getcha r. exe mystr. exe 20 000 lOWiO. exe maze. exe pri ntf.exe 5 Sleve. exe 0 Str. exe dhry. exe Whet. exe getchar. exepr printf. exe mallCC. exe Sieve. exe m 「 . exe spiro. exe lOWiO. exe Str ・ int. exe dhry. exe maze. exe ロ TC V2.0 ロ TC 十十Ⅵ .0 mallcc. exe ・・ TC 十十Ⅵ .0 ・ TC V2.0 特集 C 十十とオプジェクト指向 67
List 2 を ion 行 ( 「 5 List 3 int bp, int si) 1 : 2 : 5 : 6 : 7 : 8 : 10 : #include く stdio. h> 2 : 3 : 4 : 6 : 7 : 8 : 10 : 14 : 20 : 21 : } ックを余分確保している場合は , 1 : #include く stdio. h> #include く dos. h> int Num, 5 : char d [ 128 ] : int handler(int err, int ax, hardresume ( 0 ) : 1 1 : vo i d ma i n ( ) { harderr(handler) : do { printf("Drive ( A : 1 , B : 2. scanf("%d", &Num) : if( getcurdir(Num,d) printf("Drive Xd e ー se printf("Drive Xd } wh ⅱ e (Num トの : 燔 not ready. Yn ” Num) : 3 : char *get(void) char s [ 10 ] : scanf("Xs" return(s) : 1 1 : VO i d ma i n ( ) printf("XsYn", get()) : 3 : ma i n ( ) 2 : 1 : #include く stdio. h> List 4 Nun) : 燔 ready. Yn" 0 メモリの割り当てを行うため に , allocmem と malloc を使ってい るのですが , 正しくメモリが確保 されないことがあるようです。 A malloc や calloc などは , すべ てのメモリ管理を自分自身て行う ことが前提となっています。 oc mem は , これらの関数の動作に関 与せ $DOS のメモリ割り当てファ ンクション ( 48h ) を呼び出します。 このため , プログラムは ma Ⅱ oc と a Ⅱ ocmem を併用すると正しく動 作しなくなることがあります。 locmem と , ma Ⅱ OC や ca Ⅱ OC などの メモリ割り当て関数は併用しない てください。また , fopen や strdup など間接的に m 訓 oc を呼び出して いるものもあります。とくに必要 5 : 6 : 7 : 8 : 9 : Char c; = 0X80 : C printf("XxYn" printf("XxYn" (unsigned char)c) : 内容が壊されずに正しく動作する 場合もありますが , プログラムと しては正しくありません。 0 ha 。型の変数の値を 16 進数で 表示したいのですが , printf を使う と先頭に ff が表示されることがあり ます。 通常 C コンパイラは , char や sho 「 t を関数の引数として渡す場合 に , 自動的に int 型に変換されま す。 char は , とくにオプションを 指定しないかぎり sig ned 型 ( 符号 っき ) てすから , int 型に変換される 場合は符号が拡張され , 0X80 以上 の値は 16 進て 0xFF ? ? という値にな ります。これを , % X などの書式指 定て表示すると先頭に余計な ff と いう文字列が付加されてしまいま す。この場合は , 符号拡張されな いようにあらかじめ無符号の cha 「 型 (unsigned char) に変換してお くとよいてしよう。 (List 4 参照 ) A てなければ a Ⅱ ocmem を使わないよ うにしたほうがよいてしよう。 0 インラインアセンプラをふく んだプログラムをコンパイルする と , 同じ行の警告やエラーが 2 回表 示されることがありますが , なぜ ですか。 A プログラムの先頭て、 # p 「 agma in ⅱ ne を指定しなかったり , ー B オプ ションをつけずにインラインアセ ンプラを使ったプログラムをコン パイルすると , 初めて asm 文に出合 ったときに最初からコンパイルを やり直します。これは , 通常は直 接コンパイラがオプジェクトを生 成しているのに対し , インライン アセンプラを使った場合はアセン プリコードを生成しなければなら ないためてす。このとき , asm 文に 出合うまての行て発生した警告や 工ラーは , 再度コンパイルされる 段階てもう一度表示されます。コ ンパイル上 , 余計な時間がかかる 点以外てはとくに問題ありません が , インラインアセンプラを使う 場合 , #pragma inline 指令か , —B オプションを使うようにしてくだ さい 0 TurbO Debugger 2 . 0 で , TD386 と NEC の MS-DOS に付属し ている RAMD 旧 K. SYS を使用する 場合のオプションの指定は何が必 要ですか ? A RAMDISK. SYS を使う場合 , オプションはとくに必要ありませ ん。 CONFIG. SYS て TDH386. SYS と RAMDISK. SYS を指定す るだけてす。ほかにプロテクトメ モリを使用するアプリケーション またはデバッグ中のプログラムが プロテクトメモリを使用する場合 にはそのサイズをオプションて指 定する必要がありますが , そのア プリケーションが 0 : 401 番地 ( 使用 可能なプロテクトメモリサイズ ) を 設定している場合はそのかぎりて はありません。 lnformation from Compiler Makers 159