2008-09-02 175 views
1

由於標題已經聲明,我試圖聲明一個嵌套函數並返回一個指向該函數的指針。我希望這個函數'不'返回一個新的函數指針,它將返回任何原始函數的否定。返回函數指針指向嵌套函數C

以下是我有:

someType not(someType original) { 
    int isNot(ListEntry* entry) { 
     return !original(entry); 
    } 

    someType resultFunc = calloc(1024, 1); 
    memcpy(resultFunc, &isNot, 1024); 

    return resultFunc; 
} 

SOMETYPE被定義爲:

typedef int(*someType)(ListEntry* entry) 

回答

0

我使用GCC。

您可以通過使用該標誌打開嵌套函數:

-fnested-functions 
當你編譯

0

我也從來沒有聽說過C中的嵌套函數,但是如果gcc支持它,這不會按照你期望的方式工作。您只是簡單地複製isNot的機器指令,並且在調用「not」時不包括「original」的實際值。

您應該使用C++類來實現,它存儲一個指針,您可以使用「original」值初始化該指針,並從「not」返回此類的一個實例。

19

史蒂夫,你對C函數的完全錯誤的心理模型。

someType resultFunc = calloc(1024, 1); 
memcpy(resultFunc, &isNot, 1024); 

從您的代碼片段,我可以推測,你認爲你可以複製功能的編譯代碼到的內存塊,然後再用它。 Lisp的這種東西聞起來,除非在lisp中你不這樣做。

事實上,當你說「& isNot」時,你會得到一個指向函數的指針。複製指針指向的內存會適得其反 - 當您將可執行文件加載到內存中時,內存被初始化,並且不會改變。在任何情況下,編寫someFunc()都會導致核心轉儲,因爲堆內存behing someFunc無法執行 - 這可以保護您免受各種病毒的侵害。

你似乎期待在C中實現閉包。這個實現根本就不存在。與Lisp或Perl或Ruby不同,C在退出該框架後無法保留堆棧框架的元素。即使嵌套函數在某些編譯器中是允許的,我相信你不能從這些函數內部引用非全局變量。關閉關閉的事情確實是存儲狀態並實現operator()的C++對象,但它是一種完全不同的方法,並且您仍然必須手動執行操作。

更新:here是GCC文檔的相關部分。尋找「但只有包含函數(在本例中爲hack)不會退出,這種技術纔有效。」

+0

感謝您的鏈接,我最喜歡的引用是「如果你試圖在包含函數退出後通過它的地址調用嵌套函數,所有的地獄都會崩潰。」 – luke 2010-05-23 18:56:40

1

你不能以你想要的方式做到這一點。你有幾個備選方案。

您可以使用宏:

#define FN_NOT(F) !F 
#define notSomeFunc FN_NOT(someFunc) 
... 
x = notSomeFunc(entry); 

但我懷疑你希望能夠通過周圍的否定函數來取函數指針等功能,這樣就不會工作。

你可以改變你的接口來接受一些額外的信息,例如

struct closure { 
    void *env; 
    int (*f)(struct closure* extra, ListEntry*); 
}; 

static int isNot(struct closure* extra, ListEntry *entry) { 
    someType original = extra->env; 
    return !original(entry); 
} 

struct closure not(someType original) { 
    closure rv; 
    rv.env = original; 
    rv.f = &isNot; 
    return rv; 
} 

,然後用它喜歡:

struct closure inverse_fn; 
inverse_fn = not(&fn); 
if(inverse_fn.f(&inverse_fn, entry)) { 
    ... 
} 

還有其他的東西,你可以在運行時嘗試,如JIT編譯功能,但這些技術將取決於平臺和架構。這個解決方案很尷尬,但純C和便攜。