C LANGUAGE TECHNOLOGY

【C言語】goto文が有用な3つの例外

2021年4月22日

悩んでいる人
悩んでいる人

C言語のgoto文って必要なの?

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOS(Linuxカーネル)の授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
  • プログラミング歴15年以上,習得している言語: C/C++PythonSolidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開
  • 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
  • 最近は自然言語処理AIイーサリアムに関する有益な情報発信に従事.
    • (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
    • (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.

こういった私から学べます.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

goto文

goto文は,コード中の指定された場所(ラベル)に無条件にジャンプ(移動)する制御構造を持つ文です.

goto文のメリットは,自由度が高いコードを書けることです.

goto文の使い方は以下になります.

goto文のデメリットは,どこでもジャンプできることでコードが複雑になり,保守性が低くなることです.

例えば,アップル社の製品(iOS7,OSX,Safari)ではgoto文を利用したことによる脆弱性が発生しています.

なので,goto文は一般的には禁じ手と言われています.

そうすると,そもそもgoto文がなんであるのか疑問に思いますよね?

そこで,本記事ではC言語でgoto文が有用な3つの例外を紹介していきます.

また,C言語で開発された代表的なOS「Linux」におけるgoto文の利用例も取り上げます.

Linuxカーネルを学びたいあなたは,こちらからどうぞ.

C言語でgoto文が有用な3つの例外

C言語でgoto文が有用な3つの例外は以下になります.

  • 資源の獲得・解放を1:1対応にする場合
  • 多重構文から脱出する場合
  • 依存関係がある資源を獲得・解放する場合

資源の獲得・解放を1:1対応にする場合

資源の獲得・解放を1:1対応にする場合にgoto文を利用します.

C言語では,資源を獲得したら明示的に解放しなければなりません.

例えば,ファイルをfopen関数でオープンしたらfclose関数でクローズ,メモリをmalloc関数で獲得したらfree関数で解放します.

以下にメモリをmalloc関数で獲得する例を紹介します.

このコードはfunc関数でmalloc関数を呼び出してメモリを獲得していますが(14行目),free関数でメモリを解放していないのでメモリリークを起こしてしまいます.

なので,free関数を呼び出す正しいコードは以下になります.

このコードでは,malloc関数は14行目の1ヶ所で呼び出すのに対して,free関数は20行目と26行目の2ヶ所で呼び出さなくてはなりません.

よく読めば正しいコードだとわかりますが,パット見だと間違っているのでは?と疑わしいコードになってしまいます.

なので,malloc関数とfree関数の呼び出しを1:1対応にするために,goto文を利用して書き直した例が以下になります.

malloc関数は14行目の1ヶ所,free関数は26行目の1ヶ所でそれぞれ呼び出しています.

19行目のif文の返り値が0の場合,20行目で「goto end;」と書くことで25行目の「end:」にジャンプします.

このようにgoto文を利用することで,資源の獲得・解放を1:1対応にできます.

Linuxでは,kernel/sched/core.cファイルのwake_up_if_idle関数でgoto文が利用されています.

資源の獲得は6行目のrcu_read_lock関数,資源の解放は22行目のrcu_read_unlock関数で実行しています.

9行目の「goto out;」で,21行目の「out:」にジャンプします.

多重構文から脱出する場合

多重構文から脱出する場合にgoto文を利用します.

以下のコードでは,while文が13~24行目,switch文が16~23行目にあります.

scanf関数で数字を入力し,その数字がEXIT_NUMBERと等しい場合,18行目の「goto end;」で26行目の「end:」にジャンプします.

もし18行目をgoto文ではなくbreak文にする場合,switch文から脱出するだけになり,while文を再度実行してしまうことに注意して下さい.

※もちろんフラグを設定してif文を追加すれば多重構文から脱出できますが,冗長なコードになってしまいます.

Linuxでは,fs/ocfs2/super.cファイルのocfs2_parse_options関数でgoto文が利用されています.

while文が28~63行目,switch文が33~62行目にあります.

46行目で「goto bail;」で,79行目の「bail:」にジャンプします.

依存関係がある資源を獲得・解放する場合

依存関係がある資源を獲得・解放する場合にgoto文を利用します.

以下のコードでは,malloc関数とfree関数をそれぞれ3回呼び出しています.

goto文を利用することで,依存関係がある資源を獲得・解放するコードをスッキリ書けます.

※各々の資源の獲得・解放を1:1対応にしつつ多重構文を利用しないコードにもなっています.

Linuxでは,kernel/sched/core.cファイルのsched_tick_remote関数でgoto文が利用されています.

資源の獲得は22行目のrq_lock_irq関数,資源の解放は41行目のrq_unlock_irq関数で実行しています.

19行目のif文が偽の場合,20行目のgoto out_requeue;で42行目のrequeueラベルにジャンプします.

25行目のgoto out_unlock;で,40行目のout_unlock:にジャンプします.

つまり,19行目のtick_nohz_tick_stopped_cpu関数とrq_lock_irq関数の呼び出しが依存関係になっています.

まとめ

C言語でgoto文が有用な3つの例外を紹介しました.

  • 資源の獲得・解放を1:1対応にする場合
  • 多重構文から脱出する場合
  • 依存関係がある資源を獲得・解放する場合

これらの場合でgoto文を利用すると正しいコードをスッキリ書けますので,goto文の利用を検討してみてはいかがでしょうか.

goto文は以下の自作関数で利用していますので,実際のコードを知りたいあなたは,これらの記事を読みましょう!

goto文は同じ関数内でしかジャンプできませんが,他の関数にジャンプしたい場合はsetjmp/longjmp関数を利用します.

setjmp/longjmp関数の使い方を学びたいあなたはこちらからどうぞ.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , , , , , ,