『Cプログラミング診断室』目次次(第12章 芸術的字下げ 単純に)

第12章 芸術的字下げ

エラー処理を先に


エラーの発生を捕らえるには、if文を使わざるをえません。では、エラーはどう処理すればよい でしょうか。このプログラムでは、if文のelseブロックがエラー処理になっていました。

つまり、原作者のやり方で、if文のネストが12−2段の場合は次のようになります。

        if( 正常条件 ) {
                if( 正常条件 ) {
                        正常処理
                } else {
                        エラー処理
                }
        } else {
                エラー処理
        }
この方法で段数が増えれば、条件とエラー処理との距離は、どんどん伸びていきます。これは条 件が複雑になったのだからしかたがないと思ってはいけません。こんな方法で書いているからいけ ないのです。では、どうすればよいでしょうか。

もう分かりますよね。ifの条件が「真」のとき、エラーになるようにすれば、ifの直後のブロッ クが対応するエラー処理となります。したがって、上の例は次のようになります。

        if( エラー条件 ) {
                エラー処理
        }
        if( エラー条件 ) {
                エラー処理
        }
        正常処理
この方法では、条件判定がいくら増えてもネストは深くなりません。エラー処理の部分は、その 場で処理してから return するか、関数の終りに用意した共通エラー処理部にgoto文で飛ばすなど の方法を取ります。

処理内容には一切変更を加えず、エラー判定直後にエラー処理するように変更したものがリスト 12−2です。ネストが深くなっていないことが分かるでしょう。コメントを加えましたが、正常 処理の流れが、上から下へ、淡々と流れていることが分かるでしょう。ネストが深くならないので、 「つまらない」感じを与えますが、平易なことが一番肝心なのです。

リスト12−2 修正版(その1) エラー処理を先にする

     1  int     file_copyfile( filed, files, job, page, comment )
     2    char  *filed;         /* 複写先ファイル名 */
     3    char  *files;         /* 複写元ファイル名 */
     4    char  *job;           /* 複写先JOB名 */
     5    char  *page;          /* 複写先頁番号 */
     6    char  *comment;       /* 複写先コメント */
     7  {
     8          int             ret;
     9          int             fhs, fhd;
    10          int             size, rsize, wsize;
    11          char            *buff = NULL;
    12          int             pos;
    13          SYS_PAGE_HEAD   head;
    14          BASE_INFO       destbase;
    15                                                  /* 複写先ファイルの存在確認 */
    16          fhd = open( filed, O_RDONLY );
    17          if( fhd != -1 ) {
    18                  close( fhd );
    19                  ret = notice_prompt( master_menu_panel, NULL,
    20                                       NOTICE_MESSAGE_STRINGS,
    21                                              SYS_MESSAGE_SAVE_OWRITE1,
    22                                              SYS_MESSAGE_SAVE_OWRITE2,
    23                                              NULL,
    24                                       NOTICE_BUTTON_YES, SYS_TEXT_YES,
    25                                       NOTICE_BUTTON_NO, SYS_TEXT_NO,
    26                                       NULL );
    27                  if ( ret != NOTICE_YES )
    28                          return -2;
    29          }
    30                                                  /* 複写元ファイルのオープン */
    31          ret = NORMAL;
    32          fhs = open( files, O_RDONLY );
    33          if( fhs == -1 ) {
    34                  notice_prompt( master_menu_panel, NULL,
    35                                  NOTICE_MESSAGE_STRINGS,
    36                                          SYS_MESSAGE_FILEOPENS,
    37                                          SYS_MESSAGE_FILECOPYE,
    38                                          NULL,
    39                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
    40                                  NULL );
    41                  return  ERROR;
    42          }
    43                                                  /* 複写先ファイルのオープン */
    44          fhd = open( filed, O_CREAT | O_TRUNC | O_WRONLY, 00660 );
    45          if( fhd == -1 ) {
    46                  close( fhs );
    47                  notice_prompt( master_menu_panel, NULL,
    48                                  NOTICE_MESSAGE_STRINGS,
    49                                          SYS_MESSAGE_FILEOPEND,
    50                                          SYS_MESSAGE_FILECOPYE,
    51                                          NULL,
    52                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
    53                                  NULL );
    54                  return  ERROR;
    55          }
    56                                                  /* ファイルコピーバッファの確保 */
    57          size = KB_SIZE;
    58          buff = malloc( size );
    59          if ( buff == NULL ) {
    60                  notice_prompt( master_menu_panel, NULL,
    61                                  NOTICE_MESSAGE_STRINGS,
    62                                          SYS_MESSAGE_FILEMEM,
    63                                          SYS_MESSAGE_FILECOPYE,
    64                                          NULL,
    65                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
    66                                  NULL );
    67                  ret = ERROR;
    68                  goto finish;
    69          }
    70  
    71          for(;;) {
    72                  rsize = read( fhs, buff, size );        /* ファイル読み込み */
    73                  if( rsize == 0 )                /* ファイル終端 */
    74                          break;
    75                  if( rsize == -1 ) {             /* 読み込みエラー */
    76                          notice_prompt( master_menu_panel, NULL,
    77                                          NOTICE_MESSAGE_STRINGS,
    78                                                  SYS_MESSAGE_FILEREAD,
    79                                                  SYS_MESSAGE_FILECOPYE,
    80                                                  NULL,
    81                                          NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
    82                                          NULL );
    83                          ret = ERROR;
    84                          break;
    85                  }
    86                  wsize = write( fhd, buff, rsize );      /* ファイル書き込み */
    87                  if ( wsize != rsize ) {         /* 書き込みエラー */
    88                          notice_prompt( master_menu_panel, NULL,
    89                                          NOTICE_MESSAGE_STRINGS,
    90                                                  SYS_MESSAGE_FILEWRITE,
    91                                                  SYS_MESSAGE_FILECOPYE,
    92                                                  NULL,
    93                                          NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
    94                                          NULL );
    95                          ret = ERROR;
    96                          break;
    97                  }
    98          }
    99          free( buff );
   100                                                          /* 複写元ファイルの先頭へ */
   101          pos = lseek( fhs, 0, SEEK_SET );
   102          if ( pos != 0 ) {
   103                  notice_prompt( master_menu_panel, NULL,
   104                                  NOTICE_MESSAGE_STRINGS,
   105                                          SYS_MESSAGE_FILEREAD,
   106                                          SYS_MESSAGE_FILECOPYE,
   107                                          NULL,
   108                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   109                                  NULL );
   110                  ret = ERROR;
   111                  goto finish;
   112          }
   113                                                          /* ヘッダー部読み込み */
   114          size = read( fhs, &head, sizeof( SYS_PAGE_HEAD ) );
   115          if ( size != sizeof( SYS_PAGE_HEAD ) ) {
   116                  notice_prompt( master_menu_panel, NULL,
   117                                  NOTICE_MESSAGE_STRINGS,
   118                                          SYS_MESSAGE_FILEREAD,
   119                                          SYS_MESSAGE_FILECOPYE,
   120                                          NULL,
   121                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   122                                  NULL );
   123                  ret = ERROR;
   124                  goto finish;
   125          }
   126                                                          /* 変更部分に位置合わせ */
   127          if ( lseek( fhs, head.base_pos, SEEK_SET ) != head.base_pos ||
   128               lseek( fhd, head.base_pos, SEEK_SET ) != head.base_pos ) {
   129                  notice_prompt( master_menu_panel, NULL,
   130                                  NOTICE_MESSAGE_STRINGS,
   131                                          SYS_MESSAGE_FILEWRITE,
   132                                          SYS_MESSAGE_FILECOPYE,
   133                                          NULL,
   134                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   135                                  NULL );
   136                  ret = ERROR;
   137                  goto finish;
   138          }
   139                                                          /* 変更部分の読み込み */
   140          size = read( fhs, &destbase, head.base_size );
   141          if ( size != head.base_size ) {
   142                  notice_prompt( master_menu_panel, NULL,
   143                                  NOTICE_MESSAGE_STRINGS,
   144                                          SYS_MESSAGE_FILEREAD,
   145                                          SYS_MESSAGE_FILECOPYE,
   146                                          NULL,
   147                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   148                                  NULL );
   149                  ret = ERROR;
   150                  goto finish;
   151          }
   152                                                          /* 変更 */
   153          strncpy( destbase.job_name, job, JOBNAME_LEN );
   154          strncpy( destbase.page_no, page, PAGENO_LEN );
   155          strncpy( destbase.comment, comment,COMMENT_LEN);
   156                                                          /* 変更部分の書き込み */
   157          size = write( fhd, &destbase,head.base_size);
   158          if ( size != head.base_size ) {
   159                  notice_prompt( master_menu_panel, NULL,
   160                                  NOTICE_MESSAGE_STRINGS,
   161                                          SYS_MESSAGE_FILEWRITE,
   162                                          SYS_MESSAGE_FILECOPYE,
   163                                          NULL,
   164                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   165                                  NULL );
   166                  ret = ERROR;
   167          }
   168  
   169    finish:                       /* 後始末 */
   170          close( fhs );
   171          if ( close( fhd ) == -1 ) {
   172                  notice_prompt( master_menu_panel, NULL,
   173                                  NOTICE_MESSAGE_STRINGS,
   174                                          SYS_MESSAGE_FILEWRITE,
   175                                          SYS_MESSAGE_FILECOPYE,
   176                                          NULL,
   177                                  NOTICE_BUTTON_YES, SYS_TEXT_CHECK,
   178                                  NULL );
   179                  ret = ERROR;
   180          }
   181          if ( ret == ERROR )
   182                  unlink( filed );
   183  
   184          return  ret;
   185  }

goto文を禁止する人がいますが、「アホなgotoの使い方」をするからいけないのです。エラー処 理など、適正な個所に使うのならどんどん利用し、プログラムを読みやすくできます。

ここまで変更して、やっと人に説明できるプログラムになってきました。リスト12−2のコメ ントを集めると、この関数が何をするかが分かるようになります。

図12−1 コメント(関数仕様書)

     複写先ファイルの存在確認
     複写元ファイルのオープン
     複写先ファイルのオープン
     ファイルコピーバッファの確保    
     for(;;)
  	ファイル読み込み
            ファイル終端
            読み込みエラー
        ファイル書き込み
            書き込みエラー
     複写元ファイルの先頭へ
     ヘッダー部読み込み
     変更部分に位置合わせ
     変更部分の読み込み
     変更
     変更部分の書き込み
     後始末


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第12章 芸術的字下げ 単純に)