簡體   English   中英

在C語法中返回指向函數的指針

[英]Returning a pointer to a function in C syntax

C中的函數指針如何工作的答案之一 一個用戶解釋了如何在返回值中使用函數指針。 這是有問題的代碼:

// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int

int (*functionFactory(int n))(int, int) {
    printf("Got parameter %d", n);
    int (*functionPtr)(int,int) = &addInt;
    return functionPtr;
}

對我來說,聲明functionFactory函數的方式非常奇怪 - 在我看來,你混淆了返回類型(指向函數的指針)和函數名稱本身(functionFactory)。

例如,當我們編寫一個返回其參數的平方的簡單函數時,我們會編寫類似的東西

int square(int n){
    return n*n;
}

顯然,我們返回的類型在左側,然后我們編寫函數名稱,然后寫入它接受的參數。 所以當我們返回一個指向函數的指針時,為什么我們不寫這樣的東西:

( int (*function)(int, int) ) functionFactory(int n) { ...

這里返回類型(它是一個函數的指針)及其細節(例如我們指向的函數返回以及它作為參數接受的內容)顯然在左邊分開,而functionFactory函數本身的名稱是對。 對我來說,我的版本似乎更合乎邏輯和清晰,為什么我們不這樣寫呢?

這不屬於聲明器語法的工作原理。 在替代方面考慮可能會有所幫助。 這是一種看待它的方法:

T    f   (); // f is a function returning T
     |
     v
T  (*p)  (); // p is a pointer to a function returning T
     |
     v
T  (*q())(); // q is a function returning a pointer to a function returning T

所以我們從函數聲明符f() 然后我們用指針(*p)替換f ,給我們聲明符(*p)() 最后我們用函數q()替換p ,給我們聲明器(*q())()

編輯

閱讀毛茸茸的宣言員時,你可能會聽到人們談論“螺旋規則”。 雖然它更像是指導而非實際規則,但它不符合以下優先規則:

T *a[N];    // a is an array of pointer to T
T (*a)[N];  // a is a pointer to an array of T
T *f();     // f is a function returning T
T (*f)();   // f is a pointer to a function returning T

postfix []()運算符的優先級高於一元* ,因此在聲明指向數組或函數的指針時需要括號。 所以當我們讀T (*q())(); ,我們從最左邊的標識符q和“螺旋”向外開始:

    +-----------+
    | +-------+ |
    | | +---+ | |         
    | | |   | | |
    T ( * q ()) ()
      | | | | | |
      | | +-+ | |
      | +-----+ |    
      +---------+

一點一點地打破它:

    q        -- q is a
    q()      -- function returning
   *q()      -- pointer to
  (*q())()   -- function returning
T (*q())();  -- T

不能聲明函數類型的數組,也不能聲明函數返回數組類型:

T a[N]();    // NOT ALLOWED 
T f()[N];    // NOT ALLOWED 

因此,在函數和數組類型的任意組合中,將始終涉及指針,因此螺旋規則成立。

下面的代碼聲明一個名為func的變量,它是一個指向函數的指針,該函數返回一個int並將兩個int作為參數:

int (*func)(int, int);

此語法模仿了在C中聲明函數的語法:

int func(int, int);

看看有多相似? 事實上,C中的函數就像指向函數的變量一樣,例如,請參閱此示例:

int funcA(int a, int b) { ... }
int (*funcB)(int, int) = funcA;

如果你調用funcA(a,b)funcB(a,b) ,它在其余代碼中不起作用,是嗎? 所以即使funcB是一個變量而funcA是一個函數,事實是,在內存中有一個函數,而funcAfuncB都是指向函數代碼地址的指針。

如果你想funcAfuncA是一個常量, funcB是一個變量,所以調用funcA的編譯器輸出將不同於funcB ; 在一種情況下,它是直接調用,在一種情況下是間接調用,因為funcB的目的地可以隨時間改變。 這也是星號所說的,“我不是一個函數,我是一個函數的指針”。

重要的是要注意,在C中,星號總是在變量名旁邊,以標記一個指針變量,那么你想怎么寫它呢? 像這樣?

// Careful! Wrong!
int (int, int) *func;

這看起來更具可讀性嗎? 或者也許那樣?

// Careful! Wrong!
int ()(int, int) *func;

這種語法也不是很清楚,它也不能模仿任何其他現有的C語法。 如果你使用函數指針工作很多,傳遞它們並將它們存儲在變量中,你應該為函數指針聲明一個自己的類型:

#include  <stdio.h>

int sum ( int a, int b ) {
    return (a + b);
}

typedef int (* MathFuncType)(int, int);

MathFuncType getSumFunc ( ) {
    return &sum;
}

int main(void) {
    MathFuncType func = getSumFunc();
    printf("%d\n", func(3, 8));
    return 0;
}

http://rextester.com/GEKR20461

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM