ユーニックス総合研究所

  • home
  • archives
  • c-goto

C言語のgoto文の使い方【ラベル、ジャンプ文】

  • 作成日: 2023-02-10
  • 更新日: 2023-12-24
  • カテゴリ: C言語

C言語のgoto文の使い方

C言語にはgoto文(ゴートゥーぶん)があります。
これは特定のラベルまで処理をジャンプする文です。

この文は使いすぎるとコードの可読性が下がってしまいますが、適切に使えば大変便利に使える文です。
この記事ではgoto文の使い方と適切に使えるケースを紹介しています。

関連記事
C言語でcharをintに変換する方法
C言語でenumをtypedefして使う【列挙型】
C言語でforeachマクロを実装する方法
C言語でnull判定する方法【NULL, 比較】
C言語でできることを解説!C言語歴16年の開発者が語る
C言語でオブジェクト指向する【単一継承の方法】
C言語でグローバルに関数を使う方法
C言語でシャローコピーとディープコピーを実装する

goto文の構造

goto文は↓のような構造になっています。

goto ラベル名;  

goto文は指定のラベルに処理がジャンプします。
ジャンプの範囲は関数内になります。
関数から別の関数にジャンプすることはできません。

ラベルの構造は

ラベル名:  
    処理  

になります。
ラベルを書く場合は一緒に処理も書いておく必要があるので注意してください。
ラベル名には半角英数字、アンダーバー(_)などが使えます。ラベル名の先頭に数字は使えません。

goto文を使ったサンプルコード

goto文を使ったサンプルコードは↓になります。

    printf("Hello\n");  
    goto end;  
    printf("World!\n");  
end:  
    printf("Friend!\n");  

↑のコードを実行すると結果は↓になります。

Hello  
Friend!  

このコードではprintf()が3つ書かれています。
1つ目は「Hello」と出力し、2つ目は「World!」と出力します。
3つ目は「Friend!」です。

1つ目の「Hello」が出力された後にgoto文でラベル「end」にジャンプしています。
ですので2つ目の「World!」のprintf()はスキップされます。飛び越えてるわけですね。
そしてendラベルの直後の「Friend!」を出力するprintf()がgoto文の後に実行されます。

このようにgoto文はジャンプによって特定のコードを省略します。
またこのサンプルコードでは後方にジャンプしていますが、前方にジャンプすることも可能です。

goto文を使ったテクニック

ここからはgoto文を使ったテクニックを紹介していきます。
筆者が知っているgoto文のパターンは3種類あります。
これについて記述します。
それは

  • ネストされたfor文からの脱出
  • againパターン
  • エラーハンドリング

の3つです。

ネストされたfor文からの脱出

goto文はネストされたブロックからも一挙にジャンプできます。
これを利用してネストされたfor文から脱出することができます。

    for (int i = 0; i < 4; i++) {  
        for (int j = 0; j < 4; j++) {  
            if (j == 2) {  
                goto end_for;  
            }  
        }  
    }  
end_for:  
    printf("脱出しました\n");  

goto文が無い言語の場合はフラグなどを活用して脱出しないといけませんが、goto文を使えば非常にシンプルに脱出可能です。

againパターン

againパターンというのはgoto文を使って処理をリトライするパターンです。
このパターン名は一般的ではありませんがここでは便宜的にこう呼びたいと思います。

    int a = 1;  

again:  
    if (a < 2) {  
        a++;  
        goto again;  
    } else {  
        printf("%d\n", a);  
    }  

↑のコードでは変数aには1が入ってます。
if文はa < 2が真になるのでaがインクリメントされてagainラベルにジャンプします。
そして再びif文の条件式でaが比較されて、今度はa < 2が偽になるのでelseprintf()が実行されます。

このコードは実用性は無く、あくまでagainパターンのサンプルとして書いたものです。
goto文を使うとこのように簡単に処理をリトライすることができます。
goto文が無い場合は再帰関数などを使う必要が出てきます。

エラーハンドリング

goto文はエラーハンドリングにも使われることがあります。
よくあるのが↓のようなコードです。

void error_handling(void) {  
    FILE *fin = fopen("nothing.c", "r");  
    if (fin == NULL) {  
        goto err;  
    }  

    int c;  
    while ((c = fgetc(fin)) != EOF) {  
        putchar(c);  
    }  

    fclose(fin);  
    return;  // success  
err:  
    perror("処理に失敗しました。");  
    return;  // failed  
}  

↑のコードはファイルを開いて中身を出力するコードです。
ファイルを開くのに失敗した場合はgoto err;でラベルにジャンプしています。
errラベルではperror()でエラー表示を行っています。
perror()errnoを参照してエラー出力してくれる関数です。

↑のコードを実行すると↓のような結果になります。

処理に失敗しました。: No such file or directory  

このgoto文を使ったエラーハンドリングの特徴はエラー処理を関数の後方にまとめることができるという点です。
関数で複数のエラーが発生するような場合は↑のコードのように関数の後方にエラーをまとめて処理することも出来ます。

おわりに

今回はC言語のgoto文の使い方を解説しました。
C言語のgoto文は適切に使えば便利な文です。
しかし乱用するとコードが汚くなります。

以上、何か参考になれば幸いです。

🦝 < gotoでジャンプ!

🐭 < againパターン!