2016-09-25 13 views
1

Cはネストされた関数をサポートしていないことを知っています。しかし、それでも、この動作は奇妙です。ネストされた関数を呼び出すC言語

ネストされた関数は1回しか呼び出せないようです。 2回目の呼び出しでSIGSEVが発生し、時にはSIGILLが発生します。私は、スタックのような構造のネストされた関数を必要とします。スタック上では、pop、pushなどの関数を定義することができます。入れ子関数では、通常の関数を参照で呼び出すことになります。この関数は、コンストラクタまたはイニシャライザと似ています。しかし、このコードは私の問題をシミュレートするのに十分です。

生成関数でinnerFunctionをstructに代入すると、2番目の呼び出しでエラーが発生します。代入が関数をテストするためのものであれば、2番目の呼び出しはOKです。

問題はどこですか? gccのドキュメントでは、内部関数アドレスを持っている限り、この関数にアクセスすることができ、ネストされた関数は上記で定義されたすべての変数にアクセスできます。

typedef struct A A; 

struct A { 
    void (*foo)(); 
}; 

void test() { 
    printf("test\n"); 
} 

void generate(A* a) { 

    void innerTest(){ 
     test(); 
    } 

    a->foo = &innerTest; 
} 


int main() { 

    A a; 
    generate(&a); 

    a.foo(); 
    a.foo(); 
}; 
+2

あなたの問題は何ですか?私はあなたのコードを正しくコンパイルして実行しました。 – acornagl

+0

私はネストされた関数が準拠していないと信じています。それが動作する場合でも –

+3

[ドキュメント](https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested-Functions)は実際には「*あなたのアドレスからネストされた関数を呼び出そうとすると* " – melpomene

答えて

0

内部関数へのポインタが作成されたスタックフレームをエスケープすることを許可しないでください。これにより、未定義の動作が発生します。

生成されたコードは、トランポリンをスタックに置きます。あなたが作成した特定のコンストラクトでは、関数への最初の呼び出しでトランポリンが上書きされ、関数への2回目の呼び出しで失敗しました。

私は個人的には、それが気にするために閉鎖することなくその行動を呼び出すと悩まされますが、それはそうです。 ああ、私はそれを得る待ってください。あなたの例は、これまでこれをペアにしてしまったので、誤って作業コードに減らしてしまったからです(acorngalのコメントを参照)。あなたの実際のコードは、aとラベル付けされた構造体へのポインタにアクセスするので、クロージャーを強制し、したがってトランポリンを強制します。あなたはCでこのスタントをすることはできません。オブジェクト指向プログラミングを行うときは、thisポインタに相当するものを渡す必要があります。

+0

入れ子関数のアドレスが取られたときにトランポリンが作成されます。私はまだ理解していない、なぜトランポリンが上書きされています。この行動をしない理由と解決策を説明してください。 –

+0

トランポリンは、機能から復帰するとすぐに解放されます。解放されたメモリがまだ上書きされていないため、最初の呼び出しが機能しました。ガベージコレクション不要のコンストラクタをCで作成しようとしていますが、これはガベージコレクションされません。解決策は、そこにあるガベージコレクタに依存しないように再設計することです。 – Joshua

関連する問題