2017/03/06

[c/c++]最近gotoが多い

個人的な傾向なのだが、最近エラー処理でgotoを使うことが多くなってきた。

   ret = xxx_func();
   if (!ret) {
     goto FIN;
   }
   ...

FIN:
  return -1;
}

 

goto禁止というところも多いのだが、今は自分のルールでソースを書けるため、単に個人的な傾向なのだ。
私としては「gotoの乱用はよろしくないが、局所的ならいいんじゃないの」というスタンスでいる。
C++だとtry-catchという手段もあろうが、Cだとそういうものがないので、gotoで飛ばしているのだ。

 

しばらく前は、こういう書き方をしていた。
あ、retはboolと思っておくれ。

  ret = xxx_func();
  if (ret) {
     ret = yyy_func();
  }
  if (ret) {
    ret = zzz_func();
  }
  ...

こういう書き方をしたこともあった。
本か何かで見かけたのだと思う。

do {
  ret = xxx_func();
  if (!ret) {
    break;
  }
  ret = yyy_func();
  if (!ret) {
    break;
  }
  ...
} while (0);

 

まあ、どう書くにしても、

  • 戻り値を取得
  • 戻り値をif文でチェック
  • エラーだったら何かする

という処理を書くという点は同じだ。
その見せ方や流れが違うだけだろう。

 

do-while(0)はいいかな、と思っていたのだけど、トリッキーとまでは行かないが、ちょっと変則的な気もする。
だから、ifを連続して書くパターンを使うことが多かった。
最初のチェックでNGだったら、以降もずっとNGなのに、if文のチェックを全部やらないと処理を抜けられないので、なんだかなぁ、という気持ちはあったけど、まあ複雑になるわけでもないからよいか、と思っていた。

けれど、多重ループから抜けて終わらせたい、というパターンが出てきた。
内側のループと外側のループを抜けるためにどうするか?ということを考えているうちに、だんだん面倒になってきて、もうgotoで抜ければいいやん、になったのだろう。
そして、1箇所gotoで抜けたら、他もそのルールに合わせた方が自然な流れになるか、ということで、gotoを使うことが多くなったのだと思う。

 

最近使っているmbedTLSだと、その辺をマクロで隠蔽している。
MPI_CHK()みたいなマクロがあって、戻り値をretに代入し、0以外だったらgotoでcleanupラベルに飛ばしている。
だから呼び元では、

  • ret変数の宣言
  • cleanupラベルと、その後に後始末を書く

だけやっておけば、勝手にやってくれる(ように見える)。
他のOSでは、TRY-CATCHみたいなマクロを作っていて、それはlongjump()などを隠蔽していた記憶がある。

そういうマクロがあると、ソースはさっぱりして見えて良いのだけど、何をしているか知らずに使っていると思わぬ失敗をしてしまうこともあるので、気をつけたいところだ。

かといって、マクロを用意していなかったら、各人が好き勝手にエラー処理を書いて、それはそれで読みづらくなったり、エラー処理が漏れていたりすることもあるので、リズム良く書けるのであれば良いな、と思う。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。