|
>>4388 68userさん いろいろと細かい点までアドバイスをしていただきましてありがとうございます。 大変勉強になります。 全てに指摘点に対しご回答差し上げたいのですが、 まだ指摘された部分の修正作業を行っておりませんので、 一通り読ませていただき、気づいた点について記述させていただきます。 まず return と exit の混在ですが、 これは conv_type 関数や conv_class 関数の部分だけを 指した指摘でしょうか。 それとも exit を一つも使わない方が良いという事でしょうか。 return と exit の混在のデメリットが分からなかったので。 後、変数 search ですが、仰るとおりインターフェースがいまいちです。 何故なら現在位置を返す関数と返さない関数が混在しているからです。 ここの処理がうまく思いつかなかったので search += 2; で逃げていました(^^;。 そして変数 search の大きな問題が仰るとおり > additional = two_bytes(&int_buf[search], &search); > search += 1; です。 ここは作った当人で無いと分からないですよね(^^;。 その理由は、開発途中で方針を変更してしまったためです。 そのため現在位置は ・解析し終わった部分の、次の部分の先頭に現在位置を合わせている所 ・解析し終わった部分の末尾に現在位置を合わせている所 の2パターンが発生してしまいました。 その代償が search += 2; と search += 1; の混在です。 ここは人に解析してもらう際にはまずいので修正します。 あと host[j] = 0; ですが、ここでは www.livedoor.com というドメイン名を 3www8livedoor3com0(数字の部分は文字ではなく、文字コード)に変換しているのですが、host[j] = 0; は ドメインの最後に文字コードの 0 を連結する と言う意味で記述しました。 何となく思ったのですが、 3www8livedoor3com0 の最後の 0 は終端という意味かな。 そう考えると仰られている意味が分かりました。 その部分に関しては、記述ミスと言うより、私の理解が間違っていたのかなと思います。 それと、int_buf は完全に逃げです(^^;。 ここの部分のうまい処理が思いつきませんでした。 他の指摘された部分につきましても、順次修正して良いものを作りたいと思います。 お忙しい中、いろいろご指摘いただきありがとうございます。 |
|
>>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 である環境は見たことはないですが。 |