ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は謹んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.3250

関数の引数について
投稿者---へろり(2005/01/05 15:04:52)


ある、関数へ引数を渡すとき、その引数が非常に下位の関数でしか
使われない(途中の関数は次の関数へその引数を渡すだけ)場合、
どのようにしたらいいのか非常に悩んでいます。

構造体に含めるというのも一つの手ですが、その引数が何かしらのフラグで、
一時的にしか使われないといった場合にはなんだかすっきりしないものがあります。
また、その関数の引数用の構造体をわざわざ用意するというのも雅に欠けるように
思います。

これは設計そのものが悪いのでしょうか。
上記の問題について普通はどういう風にしたらいいのでしょうか。
何かいい手がありましたらよろしくお願いします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数の引数について 3251 あかま 2005/01/05 16:19:52
<子記事> Re:関数の引数について 3252 2005/01/05 16:44:42
<子記事> Re:関数の引数について 3253 Craft 2005/01/05 17:23:07


No.3251

Re:関数の引数について
投稿者---あかま(2005/01/05 16:19:52)


それは関数a()からb()を呼び出し、b()からc()を呼び出すときに
b()で使わないa()の変数をc()へ渡すのに、なにか綺麗な方法はないか?
ということで?

void a(){
    int i;
    //何かの処理
    b(i);
    return;
}
void b(int i){
    int j;
    //何かの処理
    c(i,j);
    return;
}
void c(int i,int j){
    //何かの処理
    return;
}

みたいにただ関数の最後で別の関数を呼んでいるような場合はたぶん設計が悪いと思います。
長いa()を途中で分断するために、b()とc()を作っただけのような。
機能ごとに分割すると大抵、

void a(){
    int i,j;
    //何かの処理
    j = b();
    c(i,j);
    return;
}
int b(){
    int j;
    //何かの処理
    return j;
}
void c(int i,int j){
    //何かの処理
    return;
}

のような形になると思います。
こうするとあまり深くならないので設計を見直してみては?



この投稿にコメントする

削除パスワード

No.3264

Re:関数の引数について
投稿者---へろり(2005/01/10 10:51:18)


せっかくレスをつけていただいたのに亀レスすみません。
ここのサイトを表示する際、ブラウザが投稿時のキャッシュを読み込んでた
だけだったようで、レスに気づくのが遅れました。m(_ _)m

>
それは関数a()からb()を呼び出し、b()からc()を呼び出すときに
b()で使わないa()の変数をc()へ渡すのに、なにか綺麗な方法はないか?
ということで?

まさしくその通りです。いろいろと考えてみてはいるのですが、どれも
しっくりこないのです。

void a(){
    int i;
    //何かの処理
    b(i);
    return;
}
void b(int i){
    int j;
    //何かの処理
    c(i,j);
    return;
}
void c(int i,int j){
    //何かの処理
    return;
}

みたいにただ関数の最後で別の関数を呼んでいるような場合はたぶん設計が悪いと思います。
長いa()を途中で分断するために、b()とc()を作っただけのような。
機能ごとに分割すると大抵、

void a(){
    int i,j;
    //何かの処理
    j = b();
    c(i,j);
    return;
}
int b(){
    int j;
    //何かの処理
    return j;
}
void c(int i,int j){
    //何かの処理
    return;
}

のような形になると思います。
こうするとあまり深くならないので設計を見直してみては?


なるほど。 しかし機能そのものがネストしている場合も多々あるかと思います。
たとえば下記のコードは円グラフを描画するものです。

main()
{
    draw();
}

/*円グラフ描画関数*/
draw()
{
    /*グラフの円の描画*/
    drawCircle();

    /*〜率、〜%など文字列の描画*/
    drawText();
}


上記のコードにおいてdrawCircle()関数は、円をフラットに描画したり、
立体的に描画したりする事が出来ます。
また、drawText()関数は、文字の大きさや色を任意に指定できます。

こういった場合円グラフをどのように描画するか。 という指定は、
やはりdraw()関数の引数として与えるのが自然だと考えます。
しかし、実のところその引数を必要としているのははdraw()関数内で
コールされるdrawCircle()関数であり、drawText()関数です。

また、たとえばdrawText()関数は与えられた引数を引数に見合ったフォント
を作成するのに使うかもしれませんが、フォントを作成する関数にその
引数をただ渡すだけというのもあり得ます。

上記のような場合で、途中の関数で引数を次々とスルーして行くのは
どうも釈然としません。

どうか、もう少しおつきあいください。
よろしくお願いします。


この投稿にコメントする

削除パスワード

No.3272

Re:関数の引数について
投稿者---Ban(2005/01/10 15:04:50)


>上記のような場合で、途中の関数で引数を次々とスルーして行くのは
>どうも釈然としません。

オブジェクト指向とかデザインパターンとか言い出すと、
'facade' とか 'delegation' とか '〜 proxy' とか、
そういう感じのコードが山ほど現れるようになると思います。
# 「デメテルの法則」を実現するにも重要?

その例なら、あまり悩むこともなく仲介してあげてもいいように思います。



この投稿にコメントする

削除パスワード

No.3275

Re:関数の引数について
投稿者---へろり(2005/01/11 06:55:17)


>オブジェクト指向とかデザインパターンとか言い出すと、
>'facade' とか 'delegation' とか '〜 proxy' とか、
>そういう感じのコードが山ほど現れるようになると思います。
># 「デメテルの法則」を実現するにも重要?
>

「デメテルの法則」初めて聞く単語です。
探し方が悪いのかまともに扱ってくれてるサイトが英語のサイトしか無かったので
ちょっと自信ありませんが、私はあるオブジェクトを扱う場合において、
そのオブジェクトの直接の子ども意外のオブジェクトに直接アクセス
してはならないと解釈しました。

C言語でオブジェクト指向を取り入れるならば下記のようなコードになると
思います。

/*hoge.h*/
typedef struct tagHOGE HOGE;
HOGE* initHoge();


/*hoge.c*/
#include "bar.h"

typedef struct tagHOGE{
   BAR *bar;
   ...
}HOGE;

HOGE* initHoge()
{
    HOGE *hoge = malloc(sizeof(HOGE));
    hoge->bar = initBar();
    ....
    return hoge;
}

/*bar.h*/
typedef struct tagBAR BAR;
BAR* initBar();


/*bar.c*/
typedef struct tagBAR{
    ...
}BAR;

BAR* initBar()
{
    BAR *bar = malloc(sizeof(BAR));
    ....
    return bar;
}


/*main.c*/
#include "hoge.h"

main()
{
    HOGE *hoge = initHoge;
}


なるほど、確かにmain()関数からオブジェクトHOGEが持つオブジェクトBAR
へ直接アクセスするのは避けた方がいいでしょう。

しかし、C言語においてプログラムは原則として関数の組み合わせであり、
1関数=1機能が理想であると私は考えます。
また、関数がより下層へ行くほど、より低レベルになるほどその汎用性が
高まるとも考えます。

また、C言語においてその機能(関数)は、それを必要とするモジュールへ
対しグローバルであるべきだと考えます。

>その例なら、あまり悩むこともなく仲介してあげてもいいように思います。

ので、がんばればもう少しスマートに書けそうな気がするのですが、
やはりそうするのが一番妥当なのでしょうか。



この投稿にコメントする

削除パスワード

No.3274

Re:関数の引数について
投稿者---かずま(2005/01/10 19:33:03)


>上記のコードにおいてdrawCircle()関数は、円をフラットに描画したり、
> 立体的に描画したりする事が出来ます。
> また、drawText()関数は、文字の大きさや色を任意に指定できます。
>
> こういった場合円グラフをどのように描画するか。 という指定は、
> やはりdraw()関数の引数として与えるのが自然だと考えます。
> しかし、実のところその引数を必要としているのははdraw()関数内で
> コールされるdrawCircle()関数であり、drawText()関数です。

引数を構造体へのポインタにするというのはいかがでしょうか?
typedef struct Circle {
    int mode;
} Circle;
 
typedef struct Text {
    int size;
    int color;
} Text;
 
typedef struct Data {
    Circle circle;
    Text   text;
} Data;
 
void draw(Data *data)
{
    drawCircle(&data->circle);
    drawText(&data->text);
}
 
int main(void)
{
    Data data;
    data.circle.mode = ...;
    data.text.size   = ...;
    data.text.color  = ...;
    draw(&data);
}



この投稿にコメントする

削除パスワード

No.3276

Re:関数の引数について
投稿者---へろり(2005/01/11 07:08:56)


>引数を構造体へのポインタにするというのはいかがでしょうか?
><pre>
typedef struct Circle {
int mode;
} Circle;

typedef struct Text {
int size;
int color;
} Text;

typedef struct Data {
Circle circle;
Text text;
} Data;

void draw(Data *data)
{
drawCircle(&data->circle);
drawText(&data->text);
}

int main(void)
{
Data data;
data.circle.mode = ...;
data.text.size = ...;
data.text.color = ...;
draw(&data);
}
</pre>

確かに、引数を一つにまとめて”描画用パラメータ”という意味を与える
(構造体の定義)と、非常にすっきりします。

しかし、描画が必要な場所の全てで構造体のインスタンスの生成、必要な
値の代入などを行うというのも煩雑なような気がします。
#ウィンドウズプログラムでは日常茶飯事ですが

どうせならもっと、一行一発で済ませたいと思っております。


この投稿にコメントする

削除パスワード

No.3252

Re:関数の引数について
投稿者---樽(2005/01/05 16:44:42)


>構造体に含めるというのも一つの手ですが、その引数が何かしらのフラグで、
>一時的にしか使われないといった場合にはなんだかすっきりしないものがあります。
>また、その関数の引数用の構造体をわざわざ用意するというのも雅に欠けるように
>思います。
>
>これは設計そのものが悪いのでしょうか。
>上記の問題について普通はどういう風にしたらいいのでしょうか。
>何かいい手がありましたらよろしくお願いします。

作り直しができるなら、設計から見直しを薦めますが、
改修手段としてならば、
グローバル変数にしてしまうとか
static変数を利用するのもありかと



この投稿にコメントする

削除パスワード

No.3265

Re:関数の引数について
投稿者---へろり(2005/01/10 10:57:29)


まずはあきれるほどの遅レスのお詫び申し上げます。 m(_ _)m

>作り直しができるなら、設計から見直しを薦めますが、
>改修手段としてならば、
>グローバル変数にしてしまうとか
>static変数を利用するのもありかと

渡される引数は一時的なものであり、その値も常に保持しておかなければ
ならないものではありませんので、グローバルな置いたりstatic指定を
するのは、ちょっとどうかと。

せっかくレスいただいたのにすみません。 ^^;


この投稿にコメントする

削除パスワード

No.3253

Re:関数の引数について
投稿者---Craft(2005/01/05 17:23:07)


>ある、関数へ引数を渡すとき、その引数が非常に下位の関数でしか
>使われない(途中の関数は次の関数へその引数を渡すだけ)場合、
>どのようにしたらいいのか非常に悩んでいます。

引き継いでいく関数にとって、受け渡されていく情報が何の意味もないものであるならば、設計見直しが一番よい手段です。
おそらくこの作りになっているということは、一番上位に位置する関数と、最終的にその引数を必要とする下位の関数の依存関係が非常に強いはずなので、設計を見直さずに対応される場合は、モジュール構造がおかしくならないように注意しましょう。

※以下のような、下位の関数が別ルートで呼ばれるような作りだけはさけた方がいいです。

a()->b()->c()という関係で、c()が下位モジュールとした場合、
c()はa()に依存する(a()から呼ばれるパラメータを必要とする)ので、
別ルートでd()->e()->c() という呼び方をするという使い方をされた
場合、c()に受け継ぐべき情報に変更があり、c()を直さなければならなくなった場合、収拾がつかなくなります。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity