『Cプログラミング診断室』目次次(第12章 芸術的字下げ エラー処理を先に)

第12章 芸術的字下げ

字下げ


■究極の美■

まずは、原作者オリジナルのリスト12−1をじっくりと味わってください。notice_promptと いう関数を多数の個所で呼びだしていますが、これはエラー発生時に、突然ユーザに警告用のウィ ンドを表示し、その後の実行継続をするかどうかを問い合わせするための関数です。

極めて美しいのは、93行以降のnotice_promptの並びです。字下げが見事なまでにきれいに戻っ ていき、その中にエラーメッセージ表示のための関数notice_promptが限りなく美しいハーモニー を保って配置されています。ネストも9段あり、見とれてしまう「究極の美」です。

美しい次下げということは、ふつうなら理解しやすく喜ばしいのですが、これは違います。

リスト12−1 オリジナルプログラム 究極の美(字下げ)

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

■エラー処理までの滞空時間■

エラー処理は、まずエラーであることを発見しなければいけません。ふつうは、if文の条件判定 式で発見します。

では今回の最初の問題です。どのnotice_promptがどのifに対応しているか調べてください。 notice_promptは全部で12個あり、if文は14個あるので、2つのif文にはnotice_promptは対応 しません。この対応は強力なエディタの利用者には容易ですが、リストを見ただけでは全く分かり ません。リストの拡大コピーを取り、定規で対応をつけてください。

ブロックを示す波括弧 { } が癖のある書き方なので難しいでしょう。記事を書く以上、私も調 べましたが、これはとても面倒な作業でしたので結果に自信が持てません。対応を調べ、その離れ 具合を「距離」で示しました。

表12−1 条件判定位置とエラー処理部分の距離

  条件判定位置	エラー処理位置
        if      notice_prompt    距離(行)

        17        20             3
        33      193         160
        36      180         144
        40      156         116
        46        48             2
        59        61             2
        71	        	
        74      143           69
        77      131           54
        79      119           40
        85      106           21
        91        93             2
      166      168             2
      177

if文は流れを2つに分けるという、プログラムの読みやすさを著しく損なう性質をもっています。 したがって、if文のネストが深くなれば、流れはどんどん枝分かれし、深いネストを抱えたif文は elseまでの距離が何ページも先になってしまいます。

要するに、if文をネストした場合、elseまでの距離が長くなってしまい、プログラムの流れが読 めなくなるのです。「この部分はどのifと対応しているんだっけ?」というようなものは、どんな に美しかろうと、プログラムとしての価値などまったくありません。ソースリストが、字下げで凸 凹することこそC言語らしいなどと思って説明しているような本もあるようなので注意しましょう。

たとえ「スバゲッティー」や「ざるそば」みたいなプログラムでなくても、この「距離」が長く なると難解なプログラムになってしまうのです。

■正常処理の流れ■

プログラムで一番重要なことは、まず、正常処理のときの「流れ」がどこを通るかです。つまり、 主流、本流を明確にすることです。

リスト12−1の正常処理の最後の文は、関数の最後の205行のreturn文です。では、その直前 はどこを通過したでしょう。すぐに答えられたら、あなたはこのプログラムを書いた人と同様の天 才で、どんな苛酷な、誰もが悲鳴を上げたくなるようなプログラムにも耐えられるでしょう。

では、この関数の正常処理のときの経路を示しましょう。以下の数字は行を示します。

16〜17,31〜46,70〜91,165〜178,205
リストのこの部分にマーカーで色をつけてみると、何と訳の分からない経路をたどっているかが しっかりと分かるでしょう。とくに、205行の直前が165〜178行というのは分かりづらいはずです。


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