2016-09-25 170 views
1

我知道C不支持嵌套函數,它只是一個gcc擴展。但即便如此,這種行爲也很奇怪。C語言調用嵌套函數

看起來嵌套函數只能調用一次;第二次調用導致SIGSEV,有時SIGILL。我想爲堆棧等結構嵌套函數。在堆棧中,我可以定義pop,push等功能,我將使用嵌套函數來分配函數,這些函數將引用正常的函數,我將會得到這些函數。這個函數就像一個構造函數或初始化器。但是這個代碼足以模擬我的問題。

當生成函數將innerFunction分配給struct時,第二次調用會導致錯誤。如果分配給測試功能,則第二次調用是可以的。

請問問題在哪裏?在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

不允許指向內部函數的指針轉義它們創建的堆棧幀。這產生未定義的行爲。

生成的代碼在棧上放置一個蹦牀。使用您創建的特定構造,蹦牀會在第一次調用該函數時被覆蓋,因此在第二次調用該函數時失敗。

我個人非常惱火,它在沒有關閉的情況下調用那個行爲來關心,但這就是它的作用。 哦,等我明白了。你的例子是有效的,因爲在將它配對到目前爲止,你意外地將它縮減爲工作代碼(參見acorngal的評論)。你真正的代碼訪問指向標記爲a的結構的指針,所以強制關閉並因此強制蹦牀。你不能在C中做這個特技;在進行OO編程時,您必須自己將等價物傳遞給this指針。

+0

當嵌套函數的地址被採用時,蹦牀被創建。我還是不明白,爲什麼蹦牀被覆蓋了。你能解釋一下沒有這種行爲的原因和解決辦法嗎? –

+0

只要你從功能返回,蹦牀就會被釋放。第一個調用工作,因爲釋放的內存還沒有被覆蓋。你正試圖在C中編寫一個垃圾收集需要的構造,而不是垃圾收集。解決方案是重新設計,不依賴於那裏的垃圾收集器。 – Joshua