標準入出力とエラー

システム・プログラムI

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro1-1997/1997-05-06
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html

■復習

■ファイルの属性

■errno と perror()


----------------------------------------------------------------------
   1:	/*
   2:	        errno-perror.c -- errno, perror() のテスト
   3:	        /usr/local/LECTURES/syspro-1997-shinjo/env/errno-perror.c
   4:	        $Header: errno-perror.c,v 1.1 97/05/05 17:00:28 yas Exp $
   5:	        Start: 1997/05/05 16:42:22
   6:	*/
   7:	
   8:	#include <errno.h>
   9:	
  10:	main()
  11:	{
  12:	        errno = 0 ;
  13:	        perror("0");
  14:	        errno = EACCES ;
  15:	        perror("EACCES");
  16:	}
----------------------------------------------------------------------

実行例。
----------------------------------------------------------------------
% cat Makefile [←]
CFLAGS=-g
% rm errno-perror [←]
% make errno-perror [←]
        cc -g errno-perror.c  -o errno-perror
% ./errno-perror [←]
0: エラー 0
EACCES: パーミッションがありません。
% []
----------------------------------------------------------------------

■文字単位のフィルタ

----------------------------------------------------------------------
   1:	/*
   2:	        filter-char.c -- 文字単位の簡単なフィルタ
   3:	        /usr/local/LECTURES/syspro-1997-shinjo/file/filter-char.c
   4:	        $Header: filter-char.c,v 1.3 97/05/05 18:19:54 yas Exp $
   5:	        Start: 1997/04/21 18:23:13
   6:	*/
   7:	
   8:	#include <stdio.h>      /* stdin, stdout, fopen(), fclose(), getc(), */
   9:	#include <ctype.h>      /* toupper() */
  10:	
  11:	main( argc,argv )
  12:	    int argc ;
  13:	    char *argv[] ;
  14:	{
  15:	    int i ;
  16:	    FILE *fp ;
  17:	        if( argc == 1 )
  18:	            filter_char_upper( stdin, stdout );
  19:	        else
  20:	        {
  21:	            for( i=1 ; i< argc ; i++ )
  22:	            {
  23:	                if( (fp = fopen( argv[i],"r" )) == NULL )
  24:	                {
  25:	                    perror( argv[i] );
  26:	                    exit( -1 );
  27:	                }
  28:	                filter_char_upper( fp, stdout );
  29:	                fclose( fp );
  30:	            }
  31:	        }
  32:	}
  33:	
  34:	filter_char_upper( in, out )
  35:	    FILE *in, *out ;
  36:	{
  37:	    int c ;     /* int型。char は、不可 */
  38:	        while( (c=getc(in)) != EOF )
  39:	        {
  40:	            putc( toupper(c),out );
  41:	        }
  42:	}

----------------------------------------------------------------------

fopen()は、ファイルを開くライブラリ関数である。"r" は、 読み込み専用で ファイルを開くことを意味している。fopen()は、結果として FILE 構造体へ のポインタを返す。これは、stdio.h で宣言されている配列 _iob[] の要素へ のポインタである。これは、次のようなライブラリ関数で使われる。

    fgetc()           fputs()           getc()         getw()
    fgets()           fread()           ungetc()
    fprintf()         fscanf()
    fputc()           fwrite()          putc()         putc()
    fflush()          fseek()           ftell()
    frewind()         fclose()          fdopen()       freopen()
    ferrror()         feof()            clearerr()     fileno()

このような、struct FILE を使うライブラリ関数群は、次のような名前で呼ば れる。

putc() は、第1引数で指定された文字を第2引数で与えられたストリームへ 出力する。

fclose() は、ファイルを閉じるライブラリ関数である。

実行例

----------------------------------------------------------------------
% ./filter-char [←]
abc[←]
ABC
asdfjkl;[←]
ASDFJKL;
^D
% []
----------------------------------------------------------------------

■バッファと FILE 構造体

----------------------------------------------------------------------
   1:	/*
   2:	        filestruct-print.c -- _filestruct[] の内容を表示する
   3:	        /usr/local/LECTURES/syspro-1997-shinjo/file/filestruct-print.c
   4:	        $Header: filestruct-print.c,v 1.2 97/05/05 18:58:37 yas Exp $
   5:	        Start: 1997/05/05 18:31:55
   6:	*/
   7:	
   8:	#include <stdio.h>
   9:	
  10:	main()
  11:	{
  12:	    FILE *fp ;
  13:	
  14:	        printf("stdin  == 0x%x == &_iob[%d]\n",stdin, stdin-&_iob[0] );
  15:	        printf("stdout == 0x%x == &_iob[%d]\n",stdout, stdout-&_iob[0] );
  16:	        printf("stderr == 0x%x == &_iob[%d]\n",stderr, stderr-&_iob[0] );
  17:	
  18:	        fp = fopen("filestruct-print.c","r");
  19:	        printf("fp     == 0x%x == &_iob[%d]\n",fp, fp-&_iob[0] );
  20:	
  21:	        printf("fopen()\n");
  22:	        filestruct_print( fp );
  23:	        getc( fp );
  24:	        printf("getc()\n");
  25:	        filestruct_print( fp );
  26:	        getc( fp );
  27:	        printf("getc()\n");
  28:	        filestruct_print( fp );
  29:	        fclose( fp );
  30:	        printf("fclose()\n");
  31:	        filestruct_print( fp );
  32:	}
  33:	
  34:	#if     0
  35:	typedef struct {
  36:	    int          __cnt;
  37:	    unsigned char       *__ptr;
  38:	    unsigned char       *__base;
  39:	    unsigned short       __flag;
  40:	    unsigned char        __fileL;               /* low byte of file desc */
  41:	    unsigned char        __fileH;               /* high byte of file desc */
  42:	} FILE;
  43:	#endif  0
  44:	
  45:	filestruct_print( fp )
  46:	    FILE *fp ;
  47:	{
  48:	        printf("cnt:%d, ptr:0x%x, base:0x%x, flag:0%x, fileL:%d, fileH:%d\n",
  49:	               fp->__cnt, fp->__ptr, fp->__base, fp->__flag,
  50:	               fp->__fileL,fp->__fileH);
  51:	}
----------------------------------------------------------------------
#    define getc(__p)     (--(__p)->__cnt >= 0 ? (int) *(__p)->__ptr++ : \
                        __filbuf(__p))
----------------------------------------------------------------------
cnt
バッファに入っている文字数
ptr
バッファの先頭番地(次に読む文字)
base
バッファ用に確保されているメモリ領域の先頭番地
fileL
UNIXのファイル記述子
実行結果

----------------------------------------------------------------------
% make filestruct-print [←]
        cc -g filestruct-print.c  -o filestruct-print
% ./filestruct-print  [←]
stdin  == 0x40001008 == &_iob[0]
stdout == 0x40001018 == &_iob[1]
stderr == 0x40001028 == &_iob[2]
fp     == 0x40001038 == &_iob[3]
fopen()
cnt:0, ptr:0x0, base:0x0, flag:01, fileL:3, fileH:0
getc()
cnt:1253, ptr:0x400035e1, base:0x400035e0, flag:09, fileL:3, fileH:0
getc()
cnt:1252, ptr:0x400035e2, base:0x400035e0, flag:09, fileL:3, fileH:0
fclose()
cnt:0, ptr:0x0, base:0x0, flag:00, fileL:3, fileH:0
% []
----------------------------------------------------------------------

■テキスト・ファイルとバイナリ・ファイル

UNIXでは、ファイルは、バイト列である。ファイルの内容として文字だけのも のを、テキスト・ファイルという。テキスト・ファイル以外のものは、バイナ リ・ファイルという。

UNIXのテキスト・ファイルでは、行末に \n が入っている。このようなテキス ト・ファイルは、テキスト・エディタ(emacs,mule,vi)で作られる。grep, sed, awk, sort などのフィルタで処理することができる。

テキスト・ファイルの入出力には、fgets(), fputs(), fprintf() などを使う とよい。(gets(), fscanf(), scanf() は、セキュリティ・ホールになりやす いので、なるべく使わない。)

■構造体の入出力

fread(), fwrite() を使う。

ポータビリティ(別のOSやCPUのコンピュータでも使う)を考える時には、 文字コード、バイトオーダー、浮動小数点の形式、構造体の穴に注意する。 XDR ライブラリを使えば、ポータビリティが高くなる。(XDR については、3 学期の「分散システム」で。)

----------------------------------------------------------------------
   1:	
   2:	/*
   3:	        utmp/print.c -- /etc/utmp ファイルの内容を表示するプログラム
   4:	        /usr/local/LECTURES/syspro-1997-shinjo/file/utmp-print.c
   5:	        $Header: utmp-print.c,v 1.2 97/05/05 21:38:41 yas Exp $
   6:	        Start: 1995/03/06 09:01:09
   7:	*/
   8:	
   9:	#include <stdio.h>      /* FILE, NULL, stderr */
  10:	#include <sys/types.h>  /* struct utmp */
  11:	#include <utmp.h>       /* struct utmp */
  12:	
  13:	#if     0
  14:	struct  utmp {
  15:	    char    ut_user[8];             /* User login name */
  16:	    char    ut_id[4];               /* /etc/inittab id (usually line #) */
  17:	    char    ut_line[12];            /* device name (console, lnxx) */
  18:	    pid_t   ut_pid;                 /* process id */
  19:	    short   ut_type;                /* type of entry */
  20:	    struct  exit_status {
  21:	        short   e_termination;      /* Process termination status */
  22:	        short   e_exit;             /* Process exit status */
  23:	        } ut_exit;                  /* The exit status of a process */
  24:	                                    /* marked as DEAD_PROCESS. */
  25:	    unsigned short  ut_reserved1;   /* Reserved for future use */
  26:	    time_t  ut_time;                /* time entry was made */
  27:	    char    ut_host[16];            /* host name, if remote */
  28:	    unsigned long   ut_addr;        /* Internet addr of host, if remote */
  29:	};
  30:	#endif  0
  31:	
  32:	main()
  33:	{
  34:	        utmp_print_file();
  35:	}
  36:	
  37:	utmp_print_file()
  38:	{
  39:	    struct utmp entry;
  40:	    FILE        *fp ;
  41:	        fp = fopen(  UTMP_FILE, "r" );
  42:	        if( fp == NULL )
  43:	        {
  44:	            perror( UTMP_FILE );
  45:	            exit( -1 );
  46:	        }
  47:	        while( fread(&entry, sizeof(entry),1,fp ) == 1 )
  48:	        {
  49:	            utmp_print( &entry );
  50:	        }
  51:	        fclose( fp );
  52:	}
  53:	
  54:	utmp_print( u )
  55:	    register struct utmp *u ;
  56:	{
  57:	        print_char_array( u->ut_user, sizeof(u->ut_user) );
  58:	        print_char_array( u->ut_id, sizeof(u->ut_id) );
  59:	        print_char_array( u->ut_line, sizeof(u->ut_line) );
  60:	        printf("%d ", u->ut_type );
  61:	        printf("%6d ", u->ut_pid );
  62:	        print_char_array( u->ut_host, sizeof(u->ut_host) );
  63:	        printf("%s",ctime(&u->ut_time) );
  64:	}
  65:	
  66:	print_char_array( a,len )
  67:	    char a[];
  68:	    int len ;
  69:	{
  70:	    int i ;
  71:	        for( i=0 ; i<len && a[i] ; i++ )
  72:	            putchar( a[i] );
  73:	        for( ; i<len ; i++ )
  74:	            putchar(' ');
  75:	        putchar(' ');
  76:	}
  77:	
  78:	/* ------------------------ utmp-print.c ------------------------ */
  79:	static char rcsid[] =
  80:	"$Header: utmp-print.c,v 1.2 97/05/05 21:38:41 yas Exp $" ;

----------------------------------------------------------------------
実行結果

----------------------------------------------------------------------
% ./utmp-print  [←]
              system boot  2      0                  Thu Apr  3 15:53:29 1997
              run-level 3  1      0                  Thu Apr  3 15:53:29 1997
bcheckrc brc1              8     12                  Thu Apr  3 15:53:31 1997
recovers slib              8     22                  Thu Apr  3 15:53:31 1997
brc      brc2              8     23                  Thu Apr  3 15:53:32 1997
sh       link              8     31                  Thu Apr  3 15:53:32 1997
rc       rc                8     34                  Thu Apr  3 15:54:44 1997
LOGIN    vue  console      6   9208                  Sat May  3 00:03:53 1997
yas      sb   pty/ttysb    7  29433 top              Mon May  5 16:20:57 1997
...
i??????  s0   pty/ttys0    8    910                  Thu Apr  3 18:51:23 1997
i??????  s1   pty/ttys1    8   1134                  Thu Apr  3 19:35:51 1997
i??????  sa   pty/ttysa    8   6886 canna15          Sat May  3 00:03:43 1997
i??????  p2   pty/ttyp2    8  19806                  Wed Apr 30 11:41:47 1997
yas      s2   pty/ttys2    8  29156                  Mon May  5 17:53:31 1997
...
e??????  s7   pty/ttys7    8   9379 canna15          Thu Apr 24 16:13:00 1997
% who [←]
yas        pty/ttysb    May  5 16:20
% []
----------------------------------------------------------------------

★[report] report-4,フィルタのプログラム

stdioライブラリ関数を持ちいて、次のようなフィルタを作りなさい。

文字単位のフィルタでは、getc(), fgetc(), getchar() と putc(), fputc(), putchar() などを使うとよい。行単位のフィルタでは、 fgets(), fputs(), fprintf() などを使うとよい。 (gets(), fscanf(), scanf() は、セキュリティ・ホールになりやすいので、なるべく使 わない。)

★練習問題,whoプログラム

UNIXの who コマンドと似た動きをするプログラムを作りなさい。


↑[もどる] ←[4月22日] ・[5月06日] →[5月13日]
Last updated: 1997/05/05 22:43:39
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>