[英]Calling a function through a function pointer - dereference the pointer or not? What's the difference?
[英]Calling a function through a function pointer
我不知道如何通過指針調用函數。
例如,我有這個指針: int (*ptr)() = a_function;
要調用一個函數,我必須寫這樣的東西ptr()
或(*ptr)()
這些通話之間有什么區別? 如果我寫printf("%p - %p", ptr, *ptr)
在兩種情況下我都會得到一個地址
無論哪種。
這是因為當您在表達式中使用函數時,它會立即衰減為指針-除非它是&
的操作數,否則無論如何都會獲得指向該函數的指針。
因此,當您編寫類似printf("hi")
,您將具有兩個操作數的函數調用操作符()
: printf
和一個包含一個值"hi"
的參數列表。
printf
是一個函數,而不是&
的操作數,因此函數調用operator ()
實際獲得的是函數指針 。 這就是為什么ptr()
在您的示例中起作用的原因:函數調用始終定義為與函數指針一起使用。
那么(*ptr)()
呢? 好吧, ptr
是一個函數指針,您可以對其取消引用以獲取函數...,該函數會立即衰減回指針,因此可以與()
一起使用以調用它。
同樣的情況適用於printf
(或任何其他函數)。 (*printf)()
有效的原因幾乎相同: printf
衰減到一個函數指針,該函數指針由*
取消引用到一個函數,該函數立即又衰減到一個指針。
在許多情況下,函數類型的值會衰減為函數的指針類型的值,類似於數組類型的值如何衰減至指向數組第一個元素的指針的方式。
函數調用表達式是后綴表達式E(...)
,其中E
是函數或函數指針類型的表達式。 這意味着各種調用語法都是有效的,並且都具有相同的含義:
void f(void);
void (*p)(void) = &f;
f(); // "f" is an expression of function type
p(); // "p" is an expression of pointer-to-function type
(*p)(); // *p is a function
(*f)(); // "f" decays to a pointer, "*f" dereferences that pointer
(****f)(); // like above, but continue decay and deref
(****p)(); // ditto
(**&f)(); // why not
順便說一句,沒有衰減的上下文之一是作為地址運算符的地址的操作數:因此,在&f
, f
不會衰減,而是表示實際函數,其地址被占用。 或者,當您寫p = f;
,您可以使用f
對&f
的隱式衰減。
C具有一些內置的魔術,其中包括指針和函數的等效性以及指針和數組的等效性。 因此,有時您可以“逃脫”,而不必在指針指向數組或函數時就完全取消對指針的完全取消引用。
但是,我想指出(哎呀,看看我在那兒做了什么?),C類型聲明的設計目標之一是對象的聲明和該對象的用法是相同的。
例如:
int *p; // p is a pointer to int
現在,我如何獲得一個int
?
int y = /* wait for it ... */ *p;
同樣的,
float *****p[2];
float y = *****p[0]; // or [1]
因此,如果您有以下聲明:
int (*ptr)() = a_function;
然后,我們問一個問題:“如何獲得整數?” 也就是說,如何調用指向無參數返回整數的函數的指針? 答案是復制您已經聲明的內容:
int y = (*ptr)();
是的,您可以說“ ptr是一個指針,並且函數和指向函數的指針之間具有神奇的等效性, p()
可以使用”。 但是不要。 因為現在,您沒有足夠的信心做到這一點。 因此,只要相信對於任何C聲明,如果要在最左側獲得類型,您所需要做的就是在右側使用*
, []
和()
,到達那里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.