質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C

    3711questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

実行制限のある関数の記述方法

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 339

ttyp03

score 11462

例えば変数aが有効なときにのみ動作すべき関数xがあったとします。
この場合、以下の2パターンの書き方ができると思うのですが、どちらの書き方がよいでしょうか。

1.呼び出し元で変数aを判定してからxを呼び出す

main()
{
    if(a){
        x();
    }
}

x()
{
    // 処理
}


2.x内でaを判定し、無効なら処理しない

main()
{
    x();
}

x()
{
    if(a){
        // 処理
    }
}
もしくは
x()
{
    if(!a) return;
    // 処理
}

1は、
xを呼び出す理由が明確であるが、呼び出し元が煩雑である。

2は、
xの呼び出し元はすっきり書けるが、処理が不要な場合でもxを呼んでしまう。

個人的にはプログラマの意図がわかる1を推したいですが、安全面で言えば2なんだと思います。
1と2をあわせるのが一番無難だと思いますが、過剰な気もします。
またこのようなデザインパターンを紹介している文献などありましたら教えてください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Stripe

    2017/10/13 18:15

    変数aと関数xの関係は?

    キャンセル

回答 5

checkベストアンサー

+5

もし関数xがガッツリ変数aに依存している場合は、
関数x内で止めれば良く、2は有力な選択肢かと思います。

しかし、関数xは変数aの値によらず動作可能であれば2はありえません。
何の関係もない変数aが横から出てきて、関数xの動作をせき止めるのは、
関数xの挙動や可能性が大幅に制限され、実行すべき所で実行出来なくなる危険があります。


私の考えは1寄りですね。
mainは関数x実行前に変数aを確認しておくべきでしょう。
信号を見もせずに横断歩道を渡り始め、クラクションを鳴らされ慌てて戻るようなものですからね。

コードリーディングの時も
関数xにジャンプしにいって読みに行ったものの、
最初の行で変数aにせき止められて何も動作せずに戻って来ることになります。
読みに行かなきゃよかった。

意味のない往復をやることになるので、
if (a) x();程度で済むならmainにif文を書いた方が可読性が上がる可能性もあります。


しかし、2の思想の設計も数多くあります。
HaskellのモナドやJavaScriptライブラリのjQueryでは
とりあえず実行してみて、失敗しても安全に着地してくれるという設計で作られています。

これはこれで一貫していて美しいので、
最終的には好みやプロジェクトでの合意に落ち着く問題かと思います。


もし1を採用した場合、頻度次第では憂鬱になるかと思います。
頻度が多い場合の回避策としてこんな手法を考えました。

main ()
{
  try_x();
}

try_x ()
{
  if (a) x();
}

x ()
{
  // 処理
}

関数xをラッピングし、変数aの顔色を伺う関数try_xを登場させます。
こうすることで、関数xはシンプルに保たれますし、mainもとりあえず関数xを呼んでみるという使い方ができるようになります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/13 16:45

    やはりaがどれだけxに依存しているかが判断材料になりますか。
    ラッパー化するアイデアは思いつきませんでした。
    処理の部分が重ければ可読性の向上も見込めそうです。

    キャンセル

  • 2017/10/13 16:52

    編集ありがとうございます。
    色々な意見を聞きたかったので、特に前提条件はありません。
    xとaの依存度、呼び出し元の数など。
    横断歩道の例えが笑えましたwうまい。

    キャンセル

  • 2017/10/13 16:58

    一旦これで編集完了とします。

    横断歩道の考え方も、HaskellのモナドやJSライブラリのjQueryはこの思想で、
    とりあえず試してみて、ダメでも値無しのまま安全に着地する設計思想ですね。
    一貫していれば美しいと思います。

    究極的には好みかもしれませんね。

    キャンセル

  • 2017/10/13 17:05

    やっぱり信号の下りは混ぜちゃダメだと思うので編集します。

    キャンセル

+3

おっしゃっていることはわかりますが。
一概には言えないというのが結論かと思います。

a が無効であることの頻度や、a が無効であることが異常なのか、正常なのか、はたまた警告のレベルなのかによっても変わってきます。

a が無効であることが異常であれば、呼び出しの元・先、どちらもチェックをいれるべきです。

正常であれば、呼出し先だけでもよいでしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/13 16:21

    結論としてはどちらでもいい、になるような気はしますが、どちらにするかを決定するのに頻度の面では考えていなかったので参考になりました。

    キャンセル

+3

例外処理のないC言語では、呼び出し先でエラーが発生した場合に予期せぬ動作を起こす可能性があります。
それを防ぐために可能な限りエラーチェックをした上で関数呼び出しを行うということは不測の事態に備えるためには有効なアプローチかと思います。
なので、基本的には1.の方の対処とした方がよいかと思います。

引数にnullを渡すと落ちる関数があるとして、nullで落ちるのが悪いのか、nullを渡すのが悪いのかというところです。
これはたとえ例外処理を実装した言語であったとしても、どちらかといえば呼び出し元がきちんと対応すべきものだと思います。
関数xはあれもこれも全部をお世話してあげられるわけでもありません。
もちろん、関数xはそのような制約があることを説明すべきだとも思います。

ただし、すべてのエラーの可能性を事前にチェックできるかというと、それも困難です。
十分チェックしていても、それでもエラーが起きるような場合にどのように対処するかといった話は、下記のページ等が参考になるかと思います。

IPA ISEC セキュア・プログラミング講座:C/C++言語編 第6章 フェイルセーフ:体系だてたエラーハンドリング

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/13 16:34

    自分の考え方に近い回答でした。
    0除算の可能性があるなら事前に判定するのと同じ考え方ができますね。

    キャンセル

+1

こんにちは。

関数xを多数の場所から呼び出し、常にif(a) x();の形式になるのであれば、関数内部側で判定した方が変更に強くなります。
逆に1~2箇所からしか呼び出さず、かつ、x()の実処理内でaを使う必要がないのであればif(a) x();の方がメンテナンス性が良いです。

x()の通常処理でaを使い、かつ、1~2箇所からしか呼び出さないような場合はなかなか悩ましいです。
このケースは正直どっちでも大差ないので、意味的に素直な方、もしくは、悩むようなら鉛筆転がしてさっさと決めた方がよいように思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/13 16:32

    鉛筆を転がして決めたいところですが、複数人で開発を行っていると実装方法が人によって異なるので、指針は決めたいんです。
    呼び出し元が多数かどうかで決めるのがよさそうですね。

    キャンセル

+1

xの挙動がaに依存するのであれば、aをxの引数として渡すのが筋ではないかと思うのですが。
そのうえでx内部で、aによって動作できないなら即時returnする。
※ただしxが戻り値を返す場合は、戻り値として「実行しなかった」をわかるような形にする

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/16 10:17

    引数として渡すのも手ですが、動きとしては2と同じになりますね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3711questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。