[英]array of functions, names, and arguments
我正在嘗試使用輸入(來自文件)的功能-由他們命名。
例如-在我寫的文件中
functionOne(1,2)
我成功地將函數名稱和他的參數分隔到不同的數組中-現在我有了:
funcName[] = functioOne
funcArg[0] = 1
funcArg[1] = 2
但是,現在我卡住了-如何使用它? 我試圖制作一個指向函數的指針數組,但不知道如何使用它。 有什么建議嗎? 謝謝
C沒有內省 。 在運行時,無法從字符串獲取或調用函數。
雖然有解決方法。 例如,您可以創建一個包含函數名稱和函數指針的表。 然后,您可以搜索此表以找到要調用的函數。
也許像
void functionOne(int arg1, int arg2)
{
...
}
struct
{
char *name;
void (*function)(int, int);
} functions[] = {
{ "funcitonOne", &functionOne },
};
為了使它更通用,當您有許多函數采用不同數量的參數時,要難一些。 然后,您可以像傳遞普通的參數那樣,傳遞包含參數的數組:
void functionOne(int *arguments)
{
// arguments[0] is the first arguments, etc.
...
}
相應地在結構中修改函數指針。
如果參數的類型也不同,則可以使用帶有類型標簽和值的並集的結構。
您無法在C語言中執行所需的操作。最接近的操作是,保留一個將指向各個函數的函數指針數組。 還要保留一個字符串數組,該字符串與其他數組的索引完全相同。 現在,只要獲得函數名稱,就可以對其進行解析,比較,並根據匹配的字符串的索引獲取適當的函數指針。
如何發送辯論文件-很好地做到這一點,我會說這件事-當您知道必須調用哪個函數時,就可以從文件本身中解析參數(您將知道此函數將花費2個辯論文本-因此您將獲得該行並將其解析為int
,並按預期將其double
,然后您將對其進行相應調用)。
通常, 您無法在便攜式 C11 (讀取n1570 )中做您想做的 事情 ,正如其他人所解釋的: 函數名是編譯時的事情 ,在執行時是未知的。 C編程語言沒有反射和/或內省 。 順便說一句,在優化編譯過程中,某個函數甚至可能“消失”(因此在運行時不“實際”存在,但是您的程序的行為就好像該函數存在一樣),因為它已被內聯或從可執行文件中刪除。 但是,C具有函數指針 (其類型描述了間接調用的函數的簽名)。 實際上,它們指向機器代碼 。
但是,如果您在運行例如Linux的x86-64計算機上編寫應用程序代碼,則有時可能會使用一些“骯臟”的技巧來解決某些問題,這些技巧專門針對該操作系統和指令集體系結構 :
給定像"functionOne"
(實際上是const char*
類型)這樣的字符串 ,您可以獲得指向它的函數指針(例如functionOne
,只要它具有外部鏈接 )-通過動態鏈接工具-使用帶有NULL
dlopen(3)路徑,然后是dlsym(3) 。 順便說一句,反向映射(從地址到名稱)可通過dladdr(3)獲得 。
給定一個函數指針 (或者實際上是虛擬地址空間中指向某個可執行 代碼段內的任何有效地址),如果在編譯時已知該函數的簽名,則可以間接調用它(以該函數指針的類型給出) )。
一個可能的技巧是發出一些包含C代碼的臨時文件/tmp/emittedcode.c
(在運行時),將編譯過程派生到一個臨時插件中(例如gcc -Wall -O -shared -fPIC/tmp/emittedcode.c -o /tmp/emittedplugin.so
),並使用dlopen(3) 動態加載該臨時插件/tmp/emittedplugin.so
。 確保在程序終止時清理混亂(例如,刪除所有臨時文件,也許使用atexit(3) )。
也許您想在運行時生成一些機器代碼; 然后再考慮一些JIT編譯庫,例如GCCJIT , LLVM , libjit , asmjit 。
如果您的PC未運行Linux,則可能會為您的OS和計算機找到同等的東西。 閱讀操作系統:三篇簡單的文章,以全面了解有關OS的更多信息。 閱讀特定操作系統的文檔(對於Linux,請先閱讀ALP或有關Linux編程的新書,然后閱讀intro(2) , syscalls(2) , elf(5)和相關頁面)。
順便說一句,如果您只想從程序中調用函數(從某個輸入文件中的名稱),則可以在初始化時構建一些哈希表 (或map ,可能是一棵紅黑樹 ),將函數名與函數指針相關聯,如建議的那樣在這個其他的答案。
也許您想要具有某些eval
原語的 homoiconic編程語言。 查看Common Lisp。 請注意SBCL ,它最多可以在REPL交互中編譯為動態生成的機器代碼。
也許您正在編寫一些解釋器 (通常比您想象的要困難和耗時,請閱讀《 龍書》 )。 考慮也許嵌入和使用現有的,例如Guile或Lua 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.