C LANGUAGE TECHNOLOGY

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

悩んでいる人

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

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

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOSの授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2021年の世界大学学術ランキングで20位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発
  • プログラミング歴15年以上,習得している言語: C/C++,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開

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

goto文

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

goto文を利用すると,自由度が高いコードを書くことができます.

しかし,どこでもジャンプできることでコードが複雑になり,保守性が低くなります.

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

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

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

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

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

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

Linuxカーネル
元東大教員から学ぶLinuxカーネル

こういった私から学べます. Linuxカーネルとは,オープンソースで広く使われているOSです. LinuxカーネルはAndroidに使われているので,スマホの中身を知りたいあなたにおすすめです. 目次 ...

続きを見る

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関数は15行目と21行目の2ヶ所で呼び出さなくてはなりません.

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

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

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

14行目のif文の戻り値がNULLの場合,15行目でgoto end;と書くことで20行目の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文は,以下の自作関数で利用しています.

C言語 printf関数 自作
【C言語】printf関数の自作「myprintf関数」

悩んでいる人 C言語でprintf関数の自作を教えて! こういった悩みにお答えします. こういった私から学べます. 目次1 C言語でprintf関数の自作「myprintf関数」2 printf関数の ...

続きを見る

C言語 scanf関数 自作
【C言語】scanf関数の自作「myscanf関数」

悩んでいる人 C言語でscanf関数の自作を教えて! こういった悩みにお答えします. こういった私から学べます. 目次1 C言語でscanf関数の自作「myscanf関数」2 scanf関数の自作「m ...

続きを見る

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

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

友だち追加

独学が難しいあなたは,C言語エンジニアになりたいあなたにおすすめのオンラインプログラミングスクール3社で自分に合うスクールを見つけましょう.

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

© 2021 元東大教員/アメリカのスタートアップCTO