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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

5回答

2032閲覧

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

ttyp03

総合スコア16998

C

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

0グッド

0クリップ

投稿2017/10/13 06:34

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

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

c

1main() 2{ 3 if(a){ 4 x(); 5 } 6} 7 8x() 9{ 10 // 処理 11}

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

c

1main() 2{ 3 x(); 4} 5 6x() 7{ 8 if(a){ 9 // 処理 10 } 11} 12もしくは 13x() 14{ 15 if(!a) return; 16 // 処理 17}

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2017/10/13 09:15

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

回答5

0

ベストアンサー

もし関数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を採用した場合、頻度次第では憂鬱になるかと思います。
頻度が多い場合の回避策としてこんな手法を考えました。

C

1main () 2{ 3 try_x(); 4} 5 6try_x () 7{ 8 if (a) x(); 9} 10 11x () 12{ 13 // 処理 14}

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

投稿2017/10/13 07:34

編集2017/10/13 08:18
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ttyp03

2017/10/13 07:45

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

2017/10/13 07:52

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

2017/10/13 07:58

一旦これで編集完了とします。 横断歩道の考え方も、HaskellのモナドやJSライブラリのjQueryはこの思想で、 とりあえず試してみて、ダメでも値無しのまま安全に着地する設計思想ですね。 一貫していれば美しいと思います。 究極的には好みかもしれませんね。
miyabi-sun

2017/10/13 08:05

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

0

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

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

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

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

投稿2017/10/13 06:54

編集2017/10/13 06:58
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ttyp03

2017/10/13 07:34

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

0

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

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

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

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

投稿2017/10/13 06:49

編集2017/10/13 09:13
showkit

総合スコア1638

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ttyp03

2017/10/13 07:21

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

0

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

投稿2017/10/13 08:43

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ttyp03

2017/10/16 01:17

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

0

こんにちは。

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

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

投稿2017/10/13 07:15

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ttyp03

2017/10/13 07:32

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問