68user's page 掲示板

Prev< No. 4390> Next  [最新発言に戻る] [過去ログ一覧]
No. 4390 # 68user 2005/11/12 (土) 23:12:39
>>4389 DNS勉強中
> まず return と exit の混在ですが、
main から抜ける際に return と exit が混在していることを指したつもりでした。

下請け関数から exit するのは、狙っているのなら別にいいんじゃないかと思います
(課題のプログラムですし)。変な値がやってきたら終了してしまうようでは、本格的な
運用で使うことはできませんが、

    - 本格的な運用では使えないことを認識している。
    - どういう要求が出てきたときに問題が起こるかなんとなく想像できる。
        たとえば web サーバのログから IP アドレスを拾って、複数の名前解決を
        高速に行うプログラムを作りたいという要求があったとすると、この
        プログラムではひとつでも変なレスポンスがくると exit してしまうので
        実運用には耐えられない。
    - 本格的な運用で使用する場合は、どこをどういうふうに書き換えればよいか
        だいたい把握している。

なら問題ないと思います。

> return と exit の混在のデメリットが分からなかったので。
わたしの中では以下のようなルールにしています。

    1. 基本的に main まで戻る。エラー発生時の情報出力を行うことを考えると、
          各関数の役割分担が明確になるから。

    2. 例外として、引数解析エラー表示の usage 関数内では exit してよい。
          理由は、処理が始まっておらず後始末が不要であることと、usage は
          数箇所〜数十箇所から呼ばれる可能性があり、呼び出し元での exit
          忘れが怖いこと。
              if ( argv[i][0] != '-' ){
                    usage();
                    exit(1); /* これを書き忘れると処理が続行してしまう */
              }

1 の詳細は以下のとおり。

    今回のように 1件だけのデータを処理する場合は、変な値がきたときに
          ほげフラグが 1〜5 の範囲外です
    などと出力すれば問題ないが、 一度に複数のデータを処理するバッチの場合は
          ほげフラグが 1〜5 の範囲外です。受注番号[%d] レコード番号[%d] 顧客番号 [%d]
    などとより多くの情報を出力しないと、どのデータがおかしいのか特定できない。

    とはいえ、下請け関数である 文字列→コード変換関数に、
          conv_type(query_type, order_no, rec_no, customer_no);
    などとエラー発生時に備えて各種情報を渡すのは変。エラー出力用のグローバル変数を
    作って
          err_order_no = order_no;
          err_rec_no = rec_no;
          err_customer = customer_no;
          conv_type(query_type);
    とする、なんてのも馬鹿馬鹿しい (後者はたまに見かけてイラッときますが)。

    となると、
          int main(){
              ret = file_main();
              if ( ret == -1 ){
                  logging("エラー発生。処理中断・ロールバックし、全データを元に戻します");
                  /* 後始末を一箇所にまとめる */
              }
          }

          int file_main(){
              fp = fopen(filename[i], "rw");
              while (1){
                  fgets(fp, buf, sizeof(buf));
                  ret = hoge_main(buf);
                  if ( ret == -1 ){
                      logging("hoge_main でエラー発生。ファイル名[%d] 行番号[%d]", filename[i], line);
                      return -1;
                  }
              }
          }

          int hoge_main(char *buf){
              type = conv_type(query_type);
              if ( type == -1 ){
                  logging("query_type に変換に失敗。受注番号[%d]", rec_no):
                  return -1;
              }
          }

          int conv_type(char *type){
              if ( 異常値 ){
                  logging("type が異常値 [%s]", type);
                  return -1;
              }
          }
    として main まで戻るのが現実的。conv_type はファイル名だの受注番号だの
    責任範囲外のことを知らなくてもよいが、最終的にはエラーリカバリに必要な
    情報が揃う。

Java などのいまどきな言語であれば例外を使うべきだろうと思います。


> 3www8livedoor3com0(数字の部分は文字ではなく、文字コード)に変換して
> いるのですが、host[j] = 0; は ドメインの最後に文字コードの 0 を連結
> すると言う意味で記述しました。
戻り値を
      strcpy(DNS_Send.QUERIES, make_domain(argv[2]));
と文字列として扱うのであれば、末尾は文字終端 '\0' であるべきで、
      host[j] = 0;
より
      host[j] = '\0';
にすべきという意味で書きましたが、たしかに文字列終端でもあり、DNS 的な
0 終端でもあるわけで微妙なところですね。

バイナリ列とみなして長さを明示的に管理し、strcpy のかわりに memcpy を
使うか、あるいは動作的には問題ないのでコメントで補足しておくか、あるいは
修正は不要なのか…。

> それと、int_buf は完全に逃げです(^^;。
いいんじゃないでしょうか。「バグを出さない」ということを第一目的とするなら
アリだと思います。わたしなどいまだに char と unsigned char あたりの暗黙の
型変換ではまったりしていますので、キャストがちりばめられているソースだったら
解読に苦労していたかもしれません。

ちなみに単なる「char」が signed であるか unsigned であるかは環境依存です。
とはいえ、わたしは一般的な UNIX しか知らないので、char が unsinged char
である環境は見たことはないですが。

Prev< No. 4390> Next  [最新発言に戻る] [過去ログ一覧]