『Cプログラミング診断室』目次次(第1章 普通の初心者 課題)

第1章 普通の初心者

修正プログラム


読者から送られてきたプログラム(リスト1−1)には、いっぱい問題点が含まれていて、非常 に参考になります。

オリジナルを、私のプログラムの書き方に準じて修正したものがリスト1−5です。コンパイル はしていますが、ハードがらみなので実行確認はしていません。

リスト1−5 修正版

     1  /********************************************************************************/
     2  /*                                                                              */
     3  /*                               "MLINK3.C"                                     */
     4  /*                                                                              */
     5  /*      USE             MELSEC <-> PC9801 LINK Experiment                       */
     6  /*                      USING TEX_0,1,2 (one SEND and CATCH)                    */
     7  /*                      SPECIAL EDITION                                         */
     8  /*                      (MELSEC DEBUG SPECIAL)                                  */
     9  /*                                                                              */
    10  /*      BY                                                                      */
    11  /*                                                                              */
    12  /*      OPTION      USING MRS .obj (my rs232-c source)                          */
    13  /*                        MIT1.obj (my tool-1  source)                          */
    14  /*                        MEL.obj  (MELSEC UTILITY FUNCTION source)             */
    15  /*                  make  MLINK3.MAK                                            */
    16  /*                                                                              */
    17  /*      変更履歴        1990. 4.18              MADE(DD1.C)                     */
    18  /*                            5.15              tex_* 対応                      */
    19  /*                      1991. 2.20      fuji    より美しく                      */
    20  /*                                                                              */
    21  /********************************************************************************/
    22  
    23  #include <dos.h>
    24  #include <stdio.h>
    25  #include <memory.h>
    26  #include <time.h>
    27  #include <mrs.h>
    28  #include <mit1.h>
    29  #include <mel.h>
    30  #include <process.h>
    31  #include <string.h>
    32  
    33  #define TRUE            (1)
    34  #define FALSE           (0)
    35  
    36  #define STX             0x02                    /* STX       */
    37  #define ETX             0x03                    /* ETX       */
    38  #define ENQ             0x05                    /* ENQ       */
    39  #define ACK             0x06                    /* ACK       */
    40  #define NAK             0x15                    /* NAK       */
    41  #define ESC             0x1b                    /* ESC       */
    42  
    43  #define BUFFER_SIZE             250
    44  
    45  #define BYTE_WRITE_STYLE        1
    46  #define WORD_WRITE_STYLE        2
    47  #define STATUS_READ_STYLE       3
    48  #define BYTE_READ_STYLE         4
    49  #define WORD_READ_STYLE         5
    50  #define BATCH_WRITE_STYLE       6
    51  
    52  #define WAIT                    1               /* 計算機側 待ち時間    */
    53  #define START_RENBAN            0               /* 連番 初期値          */
    54  #define FILENAME                "meldata.txt"   /* データ(text2)ファイル*/
    55  
    56  #define TEXT_1_LEN      17                      /* text1 長さ   */
    57  #define TEXT_2_LEN      13                      /* text2 長さ   */
    58  
    59  static  char    dwfname[15];                    /* データ ファイル              */
    60  static  char    dwtext2[12*4+1];                /* データ ファイル(イレコ)      */
    61  
    62  static  int     is_renzoku = FALSE;             /* 連続送り     */
    63  static  int     irenban = START_RENBAN;         /* 伝文 連番    */
    64  
    65  /*------------------------      static functions        ------------------------*/
    66  
    67  static  int     call_melsec();
    68  static  int     melsec_data_write();
    69  static  int     melsec_data_read();
    70  static  void    next_cursor_pos();
    71  static  void    status_mel();
    72  static  void    input_batch();
    73  
    74  /*------------------------------------------------------------------------------*/
    75  /*                      MELSECの呼び出し                                  */
    76  /*                                                                              */
    77  /*      戻り値:        1=ACK,  2=NAK,  3=ERR                                   */
    78  /*------------------------------------------------------------------------------*/
    79  static  int call_melsec( style, message )
    80    int   style;                                  /* 転送形式     */
    81    char  *message;                               /* 転送文字列   */
    82  {
    83          char    send_d[BUFFER_SIZE];            /* 送信メッセージ本体   */
    84          char    *type_code;                     /* 送信タイプ文字列     */
    85          char    xsum[3];                        /* サムチェック         */
    86          int     i;
    87  
    88          cls_t(3);
    89          rs_melsec();
    90  
    91          if(is_renzoku == 0){
    92                  printf("\n\n ESC キーで送信開始します \n");
    93                  while( keyin() != ESC )
    94                          ;
    95          } else {
    96                  printf("\n\n 送信開始します \n");
    97                  for( i=0 ; i < 500 ; ++i )
    98                          ;
    99          }
   100  
   101          switch(style){
   102          case BYTE_WRITE_STYLE:
   103                  type_code = "00FFBW";           break;
   104          case WORD_WRITE_STYLE:
   105                  type_code = "00FFWW";           break;
   106          case BYTE_READ_STYLE:
   107                  type_code = "00FFBR";           break;
   108          case WORD_READ_STYLE:
   109                  type_code = "00FFWR";           break;
   110          }
   111  
   112          sprintf( send_d, "%s%s", type_code, message );
   113          check_sum( send_d, xsum );
   114          strcat( send_d, xsum );
   115  
   116          rs_out1( ENQ );
   117          for( i=0 ; send_d[i] ; ++i )
   118                  rs_out1(send_d[i]);
   119          printf( "\n 送信完了、文字数  =  %d\n", i );
   120  
   121          wait_t(WAIT);
   122  
   123          switch( style ) {
   124          case BYTE_WRITE_STYLE:
   125          case WORD_WRITE_STYLE:
   126                  return   melsec_data_write( style );
   127          case BYTE_READ_STYLE:
   128          case WORD_READ_STYLE:
   129                  return   melsec_data_read( style );
   130          }
   131  }
   132  
   133  /*------------------------------------------------------------------------------*/
   134  /*                      MELSECへのデータ書き込み                          */
   135  /*------------------------------------------------------------------------------*/
   136  static  int     melsec_data_write( style )
   137    int   style;                          /* BYTE_READ_STYLE, WORD_READ_STYLE     */
   138  {
   139          int     i;
   140          int     num;                    /* 入力文字数           */
   141          char    r_code;                 /* リターン コード      */
   142          char    r_type[BUFFER_SIZE];    /* リターン コード 内容 */
   143          int     result;                 /* 結果 (1=ACK,2=NAK,3=ERR)*/
   144  
   145          num = rs_inn( 1, &r_code );
   146  
   147          switch( r_code ) {
   148          case ACK:
   149                  printf("\n ACK(正常返信)を受け取りました。");
   150                  num = rs_inn(4,r_type);
   151                  result = 1;
   152                  break;
   153          case NAK:
   154                  printf("\n NAK(異常返信)を受け取りました。");
   155                  num = rs_inn(6,r_type);
   156                  result = 2;
   157                  break;
   158          default:
   159                  printf("\n 変なコードを受け取りました。コード= %c",r_code);
   160                  result = 3;
   161                  goto ret;       /**********   エラー リターン   *********/
   162          }
   163  
   164          printf(" \nリターンコード= %c",r_code);
   165          for( i=0; i < num; i++ ) {
   166                  printf(" \n %d 番目のリターンコード= %c",i,r_type[i]);
   167          }
   168    ret:
   169          (result == 1) ? wait_t(1) : wait_key(1);
   170          rs_close();
   171          return  result;
   172  }
   173  
   174  /*------------------------------------------------------------------------------*/
   175  /*                      MELSECからデータ読み込み                          */
   176  /*------------------------------------------------------------------------------*/
   177  static  int     melsec_data_read( style )
   178    int   style;                          /* BYTE_WRITE_STYLE, WORD_WRITE_STYLE   */
   179  {
   180          char    r_code;                 /* リターン コード              */
   181          char    r_type[BUFFER_SIZE];    /* リターン コード 内容         */
   182          int     result = 1;             /* 結果 (1=ACK,2=NAK,3=ERR)     */
   183          char    xsum[3];                /* サムチェック                 */
   184          char    r_sum[3];               /* 返信 リターン サムチェック   */
   185          int     num;                    /* 入力文字数                   */
   186          int     ikk;
   187          int     i;
   188  
   189          if( (r_code = rs_in1()) != STX ) {
   190                  printf("\n 変なコードを受け取りました。コード= %c",r_code);
   191                  result = 3;     
   192                  goto ret;       /**********   エラー リターン   *********/
   193          }
   194          printf("\n 正常返信を受け取りました ");
   195  
   196          num = rs_insd( ETX, r_type );
   197          check_sum( r_type, xsum );
   198          r_sum[0] = rs_in1();
   199          r_sum[1] = rs_in1();
   200          r_sum[2] = 0x00;
   201  
   202          if( strcmpi( xsum, r_sum ) != 0 ) {
   203                  printf("\n チェックサムが違います \n");
   204                  result = 3;     
   205                  goto ret;       /**********   エラー リターン   *********/
   206          }
   207  
   208          printf(" \n リターンコード= %c",r_code);
   209          printf(" \n 局番          = %c%c",r_type[0],r_type[1]);
   210          printf(" \n PC番号      = %c%c\n\n",r_type[2],r_type[3]);
   211          i = 4;
   212          next_cursor_pos( TRUE );
   213  
   214          switch( style ) {
   215          case BYTE_READ_STYLE:
   216                  while(1){
   217                          if( r_type[i+1] == ETX ){
   218                                  printf(" \n %d 番目リターン= %c",i,r_type[i]);
   219                                  break;
   220                          }
   221                          printf(" \n %d 番目リターン= %c  |  %d 番目リターン= %c"
   222                              ,i,r_type[i],i+1,r_type[i+1]);
   223                          i += 2;
   224                          if( r_type[i] == ETX ) break;
   225                          next_cursor_pos( FALSE );
   226                  }
   227                  break;
   228          case WORD_READ_STYLE:
   229                  for( ikk=1 ; ; ikk++ ){
   230                          printf("\n   リターン %d.....%c%c%c%c",
   231                              ikk,r_type[i],r_type[i+1],r_type[i+2],r_type[i+3]);
   232                          i += 4;
   233                          if(r_type[i] == ETX ) break;
   234                          next_cursor_pos( FALSE );
   235                  }
   236          }
   237    ret:
   238          if( result == 1 ) {
   239                  printf("\n ACKコードをおくります");
   240                  send_return( 1 );                         /* return ACK */
   241          } else {
   242                  printf("\n NAKコードをおくります");
   243                  send_return( 0 );                         /* return NAK */
   244          }
   245          wait_key(1);
   246          rs_close();
   247          return  result;
   248  }
   249  
   250  /*------------------------------------------------------------------------------*/
   251  /*                              カーソル位置計算                                */
   252  /*------------------------------------------------------------------------------*/
   253  static  void    next_cursor_pos( is_init )
   254    int   is_init;
   255  {
   256          static  int     y_len;
   257  
   258          if( is_init ) {
   259                  wait_t(1);
   260                  y_len = 0;
   261                  cls_t(3);
   262                  locate(0,0);
   263          } else {
   264                  if( ++y_len >= 18 ) {
   265                          y_len = 0;
   266                          wait_key(1);
   267                          cls_t(3);
   268                          locate(0,0);
   269                  }
   270          }
   271  }
   272  
   273  /*------------------------------------------------------------------------------*/
   274  /*                              MELの状態表示                                */
   275  /*------------------------------------------------------------------------------*/
   276  static  void status_mel()
   277  {
   278          int     status;
   279          int     i;
   280          int     bit[8];
   281  
   282          rs_melsec();
   283          wait_t(WAIT);
   284  
   285          status = rs_status();
   286          for( i=0 ; i<8 ; i++ )
   287                  bit[i] = bit_out( status, i );
   288  
   289          locate(13,15);
   290          printf("\n       送信レディー       = %x   受信レディー        = %x ",
   291                  bit[0],bit[1]);
   292          printf("\n       送信データ         = %x   パリティエラー      = %x ",
   293                  bit[2],bit[3]);
   294          printf("\n       オーバーランエラー = %x   フレーミングエラー  = %x ",
   295                  bit[4],bit[5]);
   296          printf("\n       ブレーク信号       = %x   データセットレディー= %x ",
   297                  bit[6],bit[7]);
   298  
   299          wait_key(1);
   300  }
   301  
   302  /*------------------------------------------------------------------------------*/
   303  /*                              メニュー表示                                    */
   304  /*------------------------------------------------------------------------------*/
   305  static  void display_menu()
   306  {
   307          struct menu{
   308                  int     x, y;
   309                  char    *message;
   310          };
   311          const   struct  menu    menu_table[] = {
   312                  { 19, 2, "MELSEC  転送実験プログラム"     },
   313                  { 11, 4, "1.  ビット単位書き込み"             },
   314                  { 11, 6, "2.  ワード単位書き込み(tex2)"       },
   315                  { 11, 8, "3.  通信データステータス読みだし"   },
   316                  { 45, 4, "4.  ビット単位読み込み"             },
   317                  { 45, 6, "5.  ワード単位読み込み(tex1)"       },
   318                  { 45, 8, "6. バッチ実行"                     },
   319                  { 37,11, "選択して下さい (0 - 6 、0=終了)"  },
   320                  {  0, 0, NULL                                   }
   321          };      
   322  
   323          const   struct  menu    *menu_ptr;
   324  
   325          cls_t(3);
   326  
   327          for( menu_ptr=menu_table; menu_ptr->message ; ++menu_ptr ) {
   328                  locate( menu_ptr->x, menu_ptr->y );
   329                  printf( "%s", menu_ptr->message );
   330          }
   331  }
   332  
   333  /*------------------------------------------------------------------------------*/
   334  
   335  #define MESX    12
   336  #define MESY    18
   337  #define MESY0   15
   338  #define MESX1   40
   339  #define MESY1   20
   340  
   341  /*------------------------------------------------------------------------------*/
   342  /*                      パラメータの会話入力                                    */
   343  /*------------------------------------------------------------------------------*/
   344  static  void input_para( style, code1 )
   345    int   style;
   346    char  *code1;
   347  {
   348          int     yes_no;         /* y(1)  n(0)   */
   349          int     count;
   350          int     i;
   351          char    first_dev[10];
   352          char    dd[BUFFER_SIZE];
   353          char    dw;
   354  
   355          if( style == STATUS_READ_STYLE ){
   356                  status_mel();
   357                  return;
   358          }
   359  
   360  
   361          do {
   362                  locate(MESX,MESY0);     printf("コマンド=");
   363                  locate(MESX+12,MESY0);
   364                  switch( style ) {
   365                  case BYTE_WRITE_STYLE:  printf("BW"); break;
   366                  case WORD_WRITE_STYLE:  printf("WW"); break;
   367                  case BYTE_READ_STYLE:   printf("BR"); break;
   368                  case WORD_READ_STYLE:   printf("WR"); break;
   369                  }
   370  
   371                  while(1){
   372                          locate(MESX,MESY);      printf("伝文ウエイト= ");
   373                          locate(MESX+19,MESY);   scanf("%c",&dw);
   374                          if( isxdigit( dw ) )
   375                                  break;
   376                          rewind(stdin);
   377                  }
   378  
   379                  while(1){
   380                          locate(MESX,MESY+2);    printf("先頭デバイス= ");
   381                          locate(MESX+19,MESY+2); scanf( "%s", first_dev );
   382                          if( strlen( first_dev ) == 5 )
   383                                  break;
   384                  }
   385  
   386                  locate(MESX,MESY+4);    printf("デバイス点数= ");
   387                  locate(MESX+19,MESY+4);
   388                  switch( style ) {
   389                  case WORD_WRITE_STYLE:
   390                          printf( "%d", count=TEXT_2_LEN );
   391                          break;
   392                  case WORD_READ_STYLE:
   393                          printf( "%d", count=TEXT_1_LEN );
   394                          break;
   395                  default:
   396                          for( count=0 ; !((count>0) && (count<=255)) ; ) {
   397                                  locate(MESX+19,MESY+4);
   398                                  scanf( "%d", &count );
   399                          }
   400                  }
   401  
   402                  rewind(stdin);
   403                  dd[0]=0;
   404                  switch( style ) {
   405                  case BYTE_WRITE_STYLE:
   406                          for( i=0; i<count; i++ ) {
   407                                  locate(MESX1,MESY1);
   408                                  printf("データ %d   = ",i+1);
   409                                  do {
   410                                          locate(MESX1+16,MESY1);
   411                                          scanf("%c",&dd[i]);
   412                                  } while( ! ( dd[i]=='0' || dd[i]=='1' ) );
   413  
   414                                  locate(MESX1+16+i,MESY1+2);
   415                                  printf("%c",dd[i]);
   416                                  rewind(stdin);
   417                          }
   418                          dd[count]=0;
   419                          break;
   420                  case WORD_WRITE_STYLE:
   421                          sprintf( dd, "%04X%s", irenban, dwtext2 );
   422                          locate(MESX1,MESY1+2);  printf( "連番 = %X", irenban );
   423                  }
   424  
   425                  locate(MESX1+5,MESY1+4);  printf("よろしいですか(y/n)");
   426                  do {
   427                          locate(MESX1+32,MESY1+4);
   428                          yes_no = keyyn(1);
   429                  } while( ! ( yes_no==1 || yes_no == 0 ) );
   430          } while( yes_no == 0 );
   431  
   432          if( style == WORD_WRITE_STYLE )
   433                  irenban++;
   434  
   435          sprintf( code1, "%c%s%02X%s", dw, first_dev, count, dd );
   436          strupr( code1 );
   437  }
   438  
   439  /*------------------------------------------------------------------------------*/
   440  /*                              バッチ処理                                      */
   441  /*------------------------------------------------------------------------------*/
   442  static  void    input_batch()
   443  {
   444          FILE    *fdd;
   445          char    dwbname[40], dwxy[40], dwsdata[40];
   446          int     yes_no;
   447  
   448          for(;;) {
   449                  locate(MESX,MESY0);     printf("バッチファイル = ");
   450                  locate(MESX+17,MESY0);  fscanf(stdin,"%s",dwbname);
   451  
   452                  if(dwbname[0] == 'q' || dwbname[0] == 'Q' ) break;
   453  
   454                  if((fdd=fopen(dwbname,"r"))==NULL) {
   455                          locate(MESX,MESY);      printf("ファイルが有りません");
   456                          rewind(stdin);
   457                          continue;
   458                  }
   459  
   460                  locate(MESX,MESY0);     printf("転送を確認しますか(y/n)");
   461                  do {
   462                          locate(MESX+24,MESY);
   463                          yes_no = keyyn(1);              /* y(1)  n(0)   */
   464                  } while( ! ( yes_no==0 || yes_no==1 ) );
   465                  is_renzoku = (yes_no==0);               /* 'n' のとき、連続     */
   466  
   467                  locate(MESX,MESY);
   468                  cls_t(6);
   469  
   470                  while( fscanf(fdd,"%s",dwxy ) != EOF ) {
   471                          if(dwxy[0]==0x40) {
   472                                  strset(dwxy,0x00);
   473                                  continue;
   474                          }
   475  
   476                          dwxy[5]=0x00;
   477                          sprintf( dwsdata, "0%s01%s", dwxy, &dwxy[6] );
   478  
   479                          locate(MESX,MESY);      printf( "send addr. = %s",dwxy );
   480                          locate(MESX+22,MESY);   printf( "on / off  %c", dwxy[6] );
   481                          strupr(dwsdata);
   482                          wait_t(2);
   483  
   484                          if( call_melsec( BYTE_WRITE_STYLE, dwsdata ) != 1 ) {
   485                                  fclose( fdd );
   486                                  return;
   487                          }
   488                  }
   489                  break;
   490          }
   491  }
   492  
   493  /********************************************************************************/
   494  /*                              メイン・プログラム                              */
   495  /********************************************************************************/
   496  void main(int argc,char *argv[])
   497  {
   498          int     style;
   499          int     idrnd;
   500          FILE    *fd;
   501          char    cc[BUFFER_SIZE];
   502  
   503          cls_func(1);
   504  
   505          strcpy( dwfname, FILENAME );
   506          if( (fd=fopen( dwfname, "r" )) == NULL ) {
   507                  cls_t(3);
   508                  printf("\x1b[>1l");
   509                  locate(20,8);   printf("TEXT1,2用ファイルが見つかりません");
   510                  locate(29,11);  printf("終了します\n\n\n\n\n\n\n");
   511                  exit(-1);                       /********  エラー終了   *********/
   512          }
   513  
   514          fscanf(fd,"%d",&idrnd);                 /*    この辺りは理解できない    */
   515          idrnd = irenban % idrnd;
   516          fd = fd + idrnd;
   517          fscanf(fd,"%s",dwtext2);
   518          fclose(fd);
   519  
   520          do {
   521                  display_menu();
   522                  do {
   523                          locate(55,13);
   524                          style = getchar() - '0';
   525                  } while( ! ( (style >= 0) && (style <= 6)) );
   526  
   527                  switch( style ) {
   528                  case 0:
   529                          break;
   530                  case BATCH_WRITE_STYLE:
   531                          input_batch();
   532                          is_renzoku = FALSE;
   533                          break;
   534                  default:                
   535                          input_para( style, cc );
   536                          if( style != STATUS_READ_STYLE )
   537                                  call_melsec( style, cc );
   538                  }
   539          } while( style != 0 );
   540  
   541          cls_t(3);
   542          printf("\x1b[>1l");
   543          locate(29,11);  printf("終了します\n\n\n\n\n\n\n");
   544  }
   545  
   546  /********************************************************************************/
   547  /*                      EOF                  "MLINK3.C"                      */
   548  /********************************************************************************/

プログラムの書き方には個人差、個性があり、どのような書き方が「正解」とはいえません。こ こに示した修正プログラムは、私なりに、より分かりやすく、かつ元の流れをできるだけ守るよう にしたものです。もし同等のプログラムを私が新規に開発したら、全く異なったものになるでしょ う。

でも、プログラムをどのように書き換えたか2つのリストで比較検討すると、かなり参考になる のではないでしょうか。

関数の頭のコメントの書き方が、説明と違って、

   133  /*--------------------------------------------------------------*/
   134  /*              MELSECへのデータ書き込み                  */
   135  /*--------------------------------------------------------------*/
のように囲んでいます。static関数は局所的なので、より目立たないコメントということで、私 はこのようにしています。

オリジナルにはgoto文はありませんでしたが、エラー処理にはgoto文で対応してみました。goto 文も、このような使い方なら文句も言われないでしょう。


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第1章 普通の初心者 課題)