2012-02-20 82 views
9

我想我可能會患上可怕的「意外程序員」疾病,至少在涉及typedef和函數指針時。所以我一直在試驗各種涉及這些的組合來根據我得到的所有輸出結果來分析結果。typedef如何適用於函數指針

但是,當我不斷嘗試不同的組合,而不是分析結果,我現在只是迷失了過程。

我希望你們能幫我弄清楚這個爛攤子。

第一個代碼示例

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = &do_something; 
pr(); // Hello World 

第二個代碼示例

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = do_something; 
pr(); // Hello World 

如何做到既上面的代碼示例正常工作,就好像 '&' 對函數名

沒有影響

第三個代碼例如

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print pr; 
pr = do_something; // compile error 
pr = &do_something; // compile error 
pr(); 

我希望上面的任務之一在這裏工作,但該死的!我真的不明白函數指針(也可能是typedef)。

+1

這可能有助於http://stackoverflow.com/questions/4298654/operator-optional-in-function-pointer-assignment – 2012-02-20 07:25:53

+0

嗯...我認爲你應該讓自己一個'專家C編程'它explists C的變種定義規則。我會盡力爲你找到它 – shengy 2012-02-20 07:27:13

+1

只是谷歌Expert C編程,第一本書是。搜索「如何一個宣言,形成」,我想你會得到答案 – shengy 2012-02-20 07:33:10

回答

18

函數名稱和普通函數名稱的地址都表示相同的東西,所以&對函數名稱沒有影響。

同樣,使用函數指針時,多解引用是沒有問題的:

#include <stdio.h> 
typedef void print(void); 
static void dosomething(void) { printf("Hello World\n"); } 

int main(void) 
{ 
    print *f1 = dosomething; 
    print *f2 = &dosomething; 
    f2(); 
    (f1)(); 
    (*f1)(); 
    (**f2)(); 
    (***f1)(); 
    (****f2)(); 
    (*****f1)(); 
} 

這下完全編譯:

gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \ 
    -Wold-style-definition -std=c99 xx.c -o xx 

我不會聲稱多顆好作風;它不是。這很奇怪,而且(是的,你可能會這樣說)歪曲'。一個就足夠了(而且這個明星主要是針對像我這樣的人,他們在標準之前學會了用C語言編程說「沒有使用(*pointer_to_function)(arg1, arg2)表示法就可以通過指針調用函數是可以的;如果你喜歡,你可以寫pointer_to_function(arg1, arg2)」 )。是的,這很奇怪。不,沒有其他類型(或類別的類型)表現出相同的行爲,謝天謝地。

+1

現在,是奇數和,我可以說,乖張。嘗試並實際編譯。 :) – 2012-02-20 07:45:33

+4

+1,要清楚,函數和函數指針是不一樣的,但前者往往會自動衰減到在大多數情況下,後者(雖然不是全部)。在表達式'** f2'中,函數指針被取消引用,結果函數立即衰減回指針,然後再次解除引用。 – avakar 2012-02-20 07:56:23

+2

數組雖然不完全相同,但具有「自動衰減」行爲。對於'int x [10];','x'和'&x'的地址是相同的。但他們的類型是不同的,你不能使用這裏顯示的漂亮的星空塔。 – ugoren 2012-02-20 08:21:25

3

事實證明,在C/C++,既funcname&funcname將產生的funcname地址和可被分配給一個函數指針變量。這實際上是語法如何爲語言設計的一個奇怪現象。

7

關於函數指針的事情是它們是函數指針! :-)這是你如何讓你的第三個樣品的工作:

#include <stdio.h> 
typedef void (*print)(void); 
//   ^
void do_something (void) { printf("Hello World\n"); } 
int main (void) { 
    print pr; 
    pr = do_something; // &do_something would also work. 
    pr(); 
    return 0; 
} 

在是否使用funcName&funcName而言,它並不重要(在C至少)。部分6.3.2.1 Lvalues, arrays and function designators指出:

函數指示符是一個具有函數類型的表達式。除了它是sizeof運算符的操作數或一元運算符以外,類型爲「函數返回類型」的函數標識符被轉換爲具有類型「指向函數返回類型的指針」的表達式。

+0

瘋狂的第一票是downvote: -/ – 2012-02-20 07:47:12

3

像C,C++具有指針的功能:void (*)()例如是一個指向不帶參數,並沒有返回值的函數。但是,C++還引入了對函數void (&)()的引用,並且兩者之間存在隱式轉換(儘管我完全不記得這些規則)。

因此:

  • funcname是起作用
  • &funcname是起作用

注意,服用的地址(或到參考),該過載的函數需要一個指針的引用一個static_cast到確切的類型(解決超載)。