にたまごほうれん草アーカイブ

はてなダイアリーで書いてた「にたまごほうれん草」という日記のアーカイブです。現在は「にたまごほうれん草ブログ」を運営中です。

gotoを使ってみる

大学時代にCを学んだとき、誰に言われたか「gotoは基本使うな」というのがやたらと頭にあって、それ以来バカの一つ覚えみたいにgotoを知らないCプログラミングをしてきた私です。
しかし、会社に入ってから使いどころさえ間違えなければgotoは有用に使えるということを教わりました。そのときに教えてもらったのは以下のサイト。

まだ実戦では使用したことはないのですが、ちゃんとした使い方を知らないままというのも癪なのでちょっとしたコードを書いてみました。(上記のサイトでほとんど言い尽くされている感はありますが、やっぱり自分でコードを書いてみないことには実感できないかな、と)

コード

#include <stdio.h>

static int retA;
static int retB;

#define printfunc() printf("  %s\n", __FUNCTION__)

static int  initA()   { printfunc(); return retA; }
static int  initB()   { printfunc(); return retB; }
static void uninitA() { printfunc(); return; }
static void uninitB() { printfunc(); return; }

static int mainroutine() { printfunc(); return 0; }

static int testcase() {
    int ret = -1;
    if (initA() < 0) {
        goto endA; /* initA()が失敗したらすぐに戻る */
    }
    if (initB() < 0) {
        goto endB; /* initB()が失敗したらuninitAして戻る */
    }

    ret = mainroutine();

    /* mainroutine()が終わったら、uninitA()とuninitB()してから戻る */
    uninitB();
endB:
    uninitA();
endA:
    return ret;
}

int main() {
    printf("成功するケース\n");
    retA = 0;
    retB = 0;
    testcase();

    printf("initAで失敗するケース\n");
    retA = -1;
    retB = 0;
    testcase();

    printf("initBで失敗するケース\n");
    retA = 0;
    retB = -1;
    testcase();

    return 0;
}

実行結果

成功するケース
  initA
  initB
  mainroutine
  uninitB
  uninitA
initAで失敗するケース
  initA
initBで失敗するケース
  initA
  initB
  uninitA

ちゃんと思ったとおりの経路で実行してくれています。
今までだったら"goto endB;"と書いてあるところで、"uninitA(); return -1"とか書いてるところだった。