[英]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
是一個函數,事實是,在內存中有一個函數,而funcA
和funcB
都是指向函數代碼地址的指針。
如果你想funcA
, funcA
是一個常量, 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 ∑
}
int main(void) {
MathFuncType func = getSumFunc();
printf("%d\n", func(3, 8));
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.