C言語関係掲示板

過去ログ

No.575.自分自身のポインタを返す関数の宣言

[戻る] [ホームページ]
No.5349

自分自身のポインタを返す関数の宣言
投稿者---okoge(2003/02/24 17:42:00)


状態遷移の実装に今まではswitch文を使用し、各caseで状態を表していたのですが、
これだと関数が巨大になり見通しが悪い気がしていました。
そこで関数ポインタを使用して、各状態ごとに関数を分けることを考えているのですが、
自分自身のポインタを返す関数の宣言の仕方がわかりません。
今はボイドポインタとキャストでお茶を濁してますが、どうにか
typedef TSeqPtr (*TSeqPtr)(void);
のようなことをするテクニックはないでしょうか。

[test.c]
#include <stdio.h>

typedef void *(*TSeqPtr)(void);

int seq_sum;
int seq_i;

void *SeqA(void);
void *SeqB(void);
void *SeqC(void);

void *SeqA(void)
{
    seq_sum = 0;
    seq_i = 0;
    printf("初期化 : %d\n", seq_sum);
    return SeqB;
}

void *SeqB(void)
{
    seq_i++;
    seq_sum += seq_i;
    printf("処理 : %d\n", seq_i);
    return (seq_i < 10) ? SeqB : SeqC;
}

void *SeqC(void)
{
    printf("結果 : %d\n", seq_sum);
    return NULL;
}

void main(void)
{
    TSeqPtr seq = SeqA;
    do {
        seq = (TSeqPtr)seq();
    } while ( seq != NULL );
}


No.5353

Re:自分自身のポインタを返す関数の宣言
投稿者---a(2003/02/24 21:16:12)


void A(int *v,int *n){
    *n = 0;
    *v = 0;
    printf("初期化 : %d\n", *v);
}

void B(int *v ,int *n){
    (*v)++;
    *n += *v;
    printf("処理 : %d\n", *v);
}
void C(const int* n){
    printf("結果 : %d\n", *n);
}
void all_func(int val){
    int sum,plus;
    A(&plus,&sum);
    while(1){
        if(plus < val) B(&plus,&sum);
        else{ C(&sum);break;}

    }
}
typedef void (*AllFuncType)(int);
AllFuncType AllFunc(void){
    return all_func;
}
int main(void){
    all_func(10);
    AllFunc()(20);
    return 0;
}


No.5355

Re:自分自身のポインタを返す関数の宣言
投稿者---かずま(2003/02/25 02:57:30)


> 自分自身のポインタを返す関数の宣言の仕方がわかりません。
> 今はボイドポインタとキャストでお茶を濁してますが、どうにか
> typedef TSeqPtr (*TSeqPtr)(void);
> のようなことをするテクニックはないでしょうか。

ポインタではなく、ポインタをメンバに持つ構造体を返す方法が、
C-FAQ に載っていたようです。
#include <stdio.h>

typedef struct TSeq { struct TSeq (*f)(void); } TSeq;

int seq_sum;
int seq_i;

TSeq SeqA(void);
TSeq SeqB(void);
TSeq SeqC(void);

TSeq tseq[] = { NULL, SeqA, SeqB, SeqC };

TSeq SeqA(void)
{
    seq_sum = 0;
    seq_i = 0;
    printf("初期化 : %d\n", seq_sum);
    return tseq[2];
}

TSeq SeqB(void)
{
    seq_i++;
    seq_sum += seq_i;
    printf("処理 : %d\n", seq_i);
    return (seq_i < 10) ? tseq[2] : tseq[3];
}

TSeq SeqC(void)
{
    printf("結果 : %d\n", seq_sum);
    return tseq[0];
}

int main(void)
{
    TSeq seq = tseq[1];

    do {
        seq = seq.f();
    } while (seq.f != NULL);
    return 0;
}


No.5395

Re:自分自身のポインタを返す関数の宣言
投稿者---okoge(2003/02/26 17:02:34)


返信ありがとうございます。

> aさん
すいません。
私が求めていたこととは違いました。

> かずまさん
なるほど、思いつきませんでした。
例に上げていただいたソースでは飛び先が数字になっていたので、
分かりやすく関数名に出来ないものかといろいろ試してみました。
要素数が1つなんだから、そのまま
return SeqB;
とできないかなと期待したのですができませんでした。(キャストも不可)
解決はできでも手間が増えそうなので現状のままいくことにしました。
TSeq構造体の宣言がLSI-Cではエラーになったのですが、これはなぜでしょうか?


No.5405

Re:自分自身のポインタを返す関数の宣言
投稿者---かずま(2003/02/27 11:08:35)


> 例に上げていただいたソースでは飛び先が数字になっていたので、
> 分かりやすく関数名に出来ないものかといろいろ試してみました。
> 要素数が1つなんだから、そのまま
> return SeqB;
> とできないかなと期待したのですができませんでした。(キャストも不可)
TSeq tseq[] = { NULL, SeqA, SeqB, SeqC }; の代わりに、

TSeq seq0 = { NULL };
TSeq seqA = { SeqA };
TSeq seqB = { SeqB };
TSeq seqC = { SeqC };

とすれば、return tseq[2]; を return seqB; と書けます。

> TSeq構造体の宣言がLSI-Cではエラーになったのですが、これはなぜでしょうか?
struct T;
struct T f(void);
struct T (*pf)(void);

int main(void) { return 0; }
このプログラムをコンパイルしてみれば分かりますが、LSI C は不完全型を
返す関数を宣言できないようです。この場合、struct T はまだ定義されていない
のでサイズが確定していない不完全型ですが、規格では、不完全型へのポインタや
不完全型を返す関数は、そのサイズを必要としない文脈では宣言可能です。