C言語関係掲示板

過去ログ

No.1123 エラーチェック時の分岐の仕方

[戻る] [ホームページ]
No.2016

エラーチェック時の分岐の仕方
投稿者---RiSK(2004/06/14 22:46:25)


RiSKです。
初めてスレッドを立てます。よろしくお願いします。

元ツリーはNo.2006 ファイル分割プログラムです。
質問をもっと具体的にします。

エラーチェックの方法としては
if (!success) {
  // 失敗
  // エラー処理
  break;  // または return X;
}
// 成功
// :
…とエラー処理後break,returnですぐに抜ける方法と
if (success) {
  // 成功
  // :
} else {
  // 失敗
  // エラー処理
}
…のようにelseにエラー処理を持ってくる方法があると思います。
皆さんはどのようなときにどのように成功時と失敗時とを分岐させているでしょうか?

ex.
関数の大きさ、ネストの深さ、etc...で使い分ける
 それぞれ何行、何段
標準関数のfooFuncのエラー処理は必ずこうする等

上記以外のパターンでも構いませんし、
可読性等の観点からとらえていただいても構いません。

# 質問の仕方が悪ければ、引き続きご指摘願います。>ALL
## 改善されていればいいのですが…


No.2018

Re:エラーチェック時の分岐の仕方
投稿者---monkey(2004/06/15 01:04:58)


エラーチェック=例外処理と考えるならば,ワタシは原則として
    if( 例外か? )
    {
        // 例外処理
    }

    // 正常時の処理

とします.
正常時の処理が本文であり,それが見た目(インデントの深さ)でも明確に識別できるからです.


No.2049

Re:エラーチェック時の分岐の仕方
投稿者---RiSK(2004/06/15 23:41:26)


monkeyさん、レスありがとうございます。

>エラーチェックの方法としては
>エラーチェック=例外処理と考えるならば,

失礼。
 エラー処理=例外処理
 エラーチェック=例外か?=例外チェック
と読み替えてください。
# そういえば「エラーという表現はプログラマにとって曖昧」と
# どこかで読んだような気が…


>ワタシは原則として
> (snip...)
>とします.
>正常時の処理が本文であり,それが見た目(インデントの深さ)でも明確に識別できるからです.

なるほど、そのような考え方はしたことありませんでした。
逆に正常処理の流れ(monkeyさんのおっしゃる本文)が離れて見にくいと感じることが多いです。
でも、RAPTさんのおっしゃるデバッグしやすさが、私がbreak,returnを採用している理由です。
あと、ネストが深くなりにくいですし、例外チェックも漏れなく出来そうです。

ご意見ありがとうございました。


No.2019

Re:エラーチェック時の分岐の仕方
投稿者---RAPT(2004/06/15 01:18:05)


基本的にはRiSKさんと同様の書き方を好みます。
エラーチェックを最初に行なうようにしておけば、
デバッグも楽になりますし。

ただし、Cで複数個のヒープメモリやファイルのオープンを
行なう時などは、ネストした方が、書くのは楽なのですが。。

char *p = NULL, *r = NULL;
p = malloc(100);
if(p == NULL){
    return;
}
r = malloc(200);
if(r == NULL){
    free(p);
    return;
}
// ...
free(r);
free(p);

とするよりも、

char *p = NULL, *r = NULL;
p = malloc(100);
if(p){
    r = malloc(200);
    if(r){
        // ...
        free(r);
    }
    free(p);
}

とすれば、free(p) は複数個書く必要はなくなるので。

また、後処理が必要な場合は、do〜while文で書くこともあります。

char *p = NULL, *r = NULL;
int succeeded = 0;
do{
    p = malloc(100);
    if(p == NULL){
        break;
    }
    r = malloc(200);
    if(r == NULL){
        break;
    }
    // ...
    succeeded = 1;
}while(0);
if(succeeded){
    // ...
}
if(r){
    free(r);
}
if(p){
    free(p);
}


…まぁ、最近はC言語でもC++風にラップ関数っぽいのを作って
対応しちゃっていたりもしますが(^^;



No.2050

Re:エラーチェック時の分岐の仕方
投稿者---RiSK(2004/06/15 23:41:35)


ただし、Cで複数個のヒープメモリやファイルのオープンを
行なう時などは、ネストした方が、書くのは楽なのですが。。
(snip...)
とすれば、free(p) は複数個書く必要はなくなるので。
確かに。
また、後処理が必要な場合は、do〜while文で書くこともあります。
あぁ、なるほど〜。
goto ライクですけど、このテクニックは知らなかったです。
いただきます。(._.) φ メモメモ
…まぁ、最近はC言語でもC++風にラップ関数っぽいのを作って
ん? C++風が気になりますが…。
この場合、私も関数に納めたいですね。

いろんな方法がありますけど、fopen/fclose, malloc/free のネストを そろえたいという希望もあったり。
やねうBBS-はてなダイアリー感想スレ >>6の「ソースコードはアート」に同意しちゃいます。
# まぁ、私が偉そうなこと言えないのですけどね…
#「バグもアート」に関しても同意してしまいます(笑)

ご意見ありがとうございました。



No.2063

Re:エラーチェック時の分岐の仕方
投稿者---NykR(2004/06/16 14:28:40)


また、後処理が必要な場合は、do〜while文で書くこともあります。
あぁ、なるほど〜。
goto ライクですけど、このテクニックは知らなかったです。

そういうときは私は大抵gotoを使ってしまいます。

char *p = NULL, *r = NULL;
p = malloc(100);
if(p == NULL){
    goto ERROR;
}
r = malloc(200);
if(r == NULL){
    goto ERROR;
}
return // ...

ERORR:
    free(p);
    free(r);

…まぁ、最近はC言語でもC++風にラップ関数っぽいのを作って
ん? C++風が気になりますが…。

mallocに皮を被せて初期設定する関数とか、freeに皮を被せて後処理をする関数などを作るということでは?

(ex.)
void finalize_T(T ** instance_p)
{
    memset(*instance_p, 0xCC, sizeof(T));
    free(*instance_p);
    *instance_p = NULL;
}



No.2074

Re:エラーチェック時の分岐の仕方
投稿者---RiSK(2004/06/17 15:21:58)


あぁ、なるほど〜。
goto ライクですけど、このテクニックは知らなかったです。
そういうときは私は大抵gotoを使ってしまいます。
うむ。これを読んでCプログラミング診断室/最長不倒関数/Freeを思い出しました。
…まぁ、最近はC言語でもC++風にラップ関数っぽいのを作って
ん? C++風が気になりますが…。
mallocに皮を被せて初期設定する関数とか、freeに皮を被せて後処理をする関数などを作るということでは?
コンストラクタ/デストラクタっぽくという理解かな?

NykRさん、レスありがとうございました。



No.2086

Re:エラーチェック時の分岐の仕方
投稿者---RAPT(2004/06/18 01:34:53)


超適当に書いてみましたが、例えば、こんな感じです。
あとは、CStringクラスもどきや、std::find(), std::find_end() もどき
といったものを定義したこともあります。

Javaのstringクラスと同様に、ヒープメモリの先頭に長さを埋め込んでみたり。

後はTRACEマクロ(実装は デバッグ時 fprintf()でstderrに出力)とか、
主にデバッグを楽にする措置が多かったかと思います。
# 何せ、開発環境が優遇されていなかったから…(T-T)

void my_free(void **p1, void **p2)
{
  if(p1 && *p1){
    free(*p1);
    *p1 = NULL;
  }
  if(p2 && *p2){
    free(*p2);
    *p2 = NULL;
  }
}

void my_fclose(FILE **fp1, FILE **fp2)
{
  if(fp1 && *fp1){
    fclose(*fp1);
    *fp1 = NULL;
  }
  if(fp2 && *fp2){
    fclose(*fp2);
    *fp2 = NULL;
  }
}

void driver()
{
  FILE *fp = NULL;
  char *psz = NULL, *psz2 = NULL;

  fp = fopen("hoge.c", "r");
  my_fclose(&fp, NULL);

  psz = malloc(10);
  my_free(&psz, &psz2);
}