2011-07-27 49 views
0

我有一個結構數組。該結構有兩個函數指針。數組中的每個元素都需要函數指針來指向不同的函數,以便可以在不知道具體函數名稱的情況下調用與特定元素對應的函數。作爲函數指針的新手,在我看來,我正在做的事情不會奏效,但我不知道如何正確執行。如何調用被指向的函數的一個例子也是值得讚賞的。使用通用函數指針

下面是我想引用函數的原型:

int edit_translate_concise(struct ged *gedp, const union edit_cmd * const cmd); 
int edit_translate_add_arg(union edit_cmd * const cmd, struct edit_arg * const arg); 

的結構和結構的排列如下:

struct edit_cmd_tab { 
    char *name; 
    char *opt_global; 
    char *usage; 
    char *help; 
    int (*exec_concise)(struct ged *gedp, const union edit_cmd *const cmd); 
    int (*add_arg)(union edit_cmd *const cmd, struct edit_arg *const arg); 
}; 

static const struct edit_cmd_tab edit_cmds[] = { 
    ... 
    {"translate",  (char *)NULL, 
     "[FROM] TO OBJECT ...", 
     "[[-n] -k {FROM_OBJECT | FROM_POS}]\n" 
      "[-n] [-a | -r] {TO_OBJECT | TO_POS} OBJECT ...", 
     &edit_translate_concise, 
     &edit_translate_add_arg 
    }, 
    ... 
}; 

因此,功能我需要指向採用相同的參數並返回與結構的函數指針成員相同的類型。

我得到這些警告,指的是第一個結構的最後兩行:

/home/bhinesley/brlcad-trunk/src/libged/edit.c:866:55: warning: ‘union edit_cmd’ declared inside parameter list [enabled by default] 
/home/bhinesley/brlcad-trunk/src/libged/edit.c:866:55: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] 
/home/bhinesley/brlcad-trunk/src/libged/edit.c:867:54: warning: ‘union edit_cmd’ declared inside parameter list [enabled by default] 

而且這些警告指的是最後兩行排列的:

/home/bhinesley/brlcad-trunk/src/libged/edit.c:1188:2: warning: initialization from incompatible pointer type [enabled by default] 
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1188:2: warning: (near initialization for ‘edit_cmds[1].exec_concise’) [enabled by default] 
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1190:5: warning: initialization from incompatible pointer type [enabled by default] 
/home/bhinesley/brlcad-trunk/src/libged/edit.c:1190:5: warning: (near initialization for ‘edit_cmds[1].add_arg’) [enabled by default] 
+1

你(最終)在代碼中的某個地方定義了「union edit_cmd」類型嗎? –

+0

是的,它只是需要在edit_cmd_tab結構之前移動。 – bhinesley

+0

值得一提的是,這些'const'中的一些並不真正有用。它不應該導致錯誤,但它可能意味着你應該看看'cdecl'(http://cdecl.ridiculousfish.com/)以確保'const'是你想要的位置。 (尤其值得關注的是'union edit_cmd * const'作爲函數參數。) –

回答

8

你正在做[幾乎]一切正確。

但是,您必須確保實際的聯合union edit_cmd在函數原型中使用之前已經聲明。如果您忘記聲明它,編譯器會將union edit_cmd視爲全新的聯合類型的聲明,即本地函數原型。即這本地union edit_cmd聲明將與您在其他地方的union edit_cmd的實際聲明沒有任何關係。

這就是你的情況。這是編譯器試圖警告你的。這同樣適用於​​和struct edit_arg。顯然,您忘記了包含包含聲明union edit_cmd,​​和struct edit_arg的頭文件。

例如,這個簡單的代碼說明了這個問題

void foo(union bar *p); 

union bar { 
    int a; 
}; 

foo的原型宣佈union bar完全沒有關係union bar後聲明。前者是本地原型,後者是全球(即文件級別類型)。如果您稍後嘗試執行

union bar u; 
foo(&u); 

您將從編譯器獲得關於參數參數類型不匹配的診斷消息。非常相同的不匹配是導致您的帖子中的第二組警告(關於數組初始化中不兼容的指針類型)。

但是,如果你重新排列的聲明中這樣

union bar { 
    int a; 
}; 

void foo(union bar *p); 

一切工作都正常,因爲在原型union bar現指先前聲明union bar。另外,您也可以轉發,聲明union bar

union bar; 
void foo(union bar *p); 

union bar { 
    int a; 
}; 

這也將使編譯器治療union barfoo作爲全球類型(即文件級型),而不是作爲一個地方之一。

至於通過指針調用的函數,這是可以做到無論是

(*edit_cmds[i].add_arg)(/* arguments go here */); 

甚至沒有*操作

edit_cmds[i].add_arg(/* arguments go here */); 

綜上所述,容易修復的問題您正在觀察的是在函數原型

之前爲 structunion類型添加文件級前向聲明
struct ged; 
union edit_cmd; 
struct edit_arg; 
int edit_translate_concise(struct ged *gedp, const union edit_cmd * const cmd); 
int edit_translate_add_arg(union edit_cmd * const cmd, struct edit_arg * const arg); 

更優雅的方法是在原型聲明之前包含這些類型的完整定義。

+0

我知道你可以在定義結構之前定義指針,所以我認爲工會也是如此。無論如何,就是這樣,謝謝。 – bhinesley

+1

@bhinesley:結構和聯合在這方面是一樣的。問題是你不能從*函數原型*特別引用未定義的結構和聯合。 C語言中的函數原型有自己的*內部*範圍(不要問我爲什麼)。每當您從原型引用未定義的結構(或聯合)時,編譯器都會在該內部作用域中引入一個新的* local *類型。士氣:*不要參考函數原型*中未定義的結構和聯合。 – AnT

+0

啊,我明白了。 – bhinesley