假設我有一個指向 function 的指標theFunc。theFunc帶有一個指標,該指標可以指向具有與 相同引數串列的任何函式theFunc,因此被呼叫的函式可以將傳遞的指標設定為 NULL 或不同的函式。
使用它看起來像這樣:
while (funcPtr != NULL)
{
funcPtr(&funcPtr);
}
定義這是不可能的嗎?
uj5u.com熱心網友回復:
是的,這是可行的。
簡單的方法:
void (*fptr_t)(void*);
函式指標是data,即使它指向非資料。void*因此,可以在不依賴編譯器擴展的情況下轉換指向函式指標的指標。
該解決方案缺乏型別安全性。但是,它可以改進。
目前,可以宣告一個帶有未指定數量引數的函式。它允許形成不完整的函式型別。例如:
int foo();
宣告一個回傳int并接受未指定引數的函式。要使函式不帶引數,請使用int foo(void).
這允許宣告一個函式,該函式采用指向不完整函式型別的指標:
int foo(int (**)());
// call
int (*fptr)(int (**)()) = foo;
fptr(&fptr);
正如其他答案中提到的 -typedef函式型別使代碼更清晰。
typedef int foo_aux_f();
typedef int foo_f(foo_aux_f**);
foo_f *fptr = &foo;
fptr(&fptr);
通過將函式型別的宣告嵌套得越來越深,可以提高型別安全性。
typedef int foo_aux0_f();
typedef int foo_aux1_f(foo_aux0_f**);
typedef int foo_aux2_f(foo_aux1_f**);
typedef int foo_aux3_f(foo_aux2_f**);
typedef int foo_f(foo_aux3_f**);
foo_f fptr = &foo;
fptr(&fptr);
通過無限的宣告鏈可以達到完美的遞回型別,但實際上 2-3 級就足夠了。
由于對關鍵字語法的一些濫用,typedef可以壓縮這種型別的宣告:
typedef int foo_aux0_f(),
foo_aux1_f(foo_aux0_f**),
foo_aux2_f(foo_aux1_f**),
foo_aux3_f(foo_aux2_f**),
foo_f(foo_aux3_f**);
不幸的是......或者幸運的是,這個技巧可能不會在即將到來的 C23 中起作用,因為沒有原型的舊函式宣告計劃從語言中洗掉,這()意味著沒有引數,而不是未指定數量的引數。
uj5u.com熱心網友回復:
是的,您可以將指標傳遞給函式指標。如果使用 typedef,語法會容易得多。
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
void swapfunction(somefunc **ptr)
{
if(*ptr == func1) *ptr = func2;
else *ptr = func1;
}
int main(void)
{
somefunc *ptr = NULL;
swapfunction(&ptr);
ptr();
swapfunction(&ptr);
ptr();
}
您還可以使用函式回傳值:
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
somefunc *swapfunction(somefunc *ptr)
{
if(!ptr) return func1;
else if (ptr == func1) return func2;
else return NULL;
}
int main(void)
{
somefunc *ptr = NULL;
while(ptr = swapfunction(ptr))
{
ptr();
}
}
uj5u.com熱心網友回復:
參考您的 github 評論,建議您使用結構而不是型別轉換指向函式指標的指標等。這不完全是您所要求的,而是一種。代碼將如下所示:
#include <stdio.h>
struct funcArgStruct
{
void (*state)(struct funcArgStruct *);
// int extra_data; // optional
};
typedef struct funcArgStruct funcArg;
void start (funcArg *ptr);
void task1 (funcArg *ptr);
void stop (funcArg *ptr);
/* Implementation of an fsm. */
int main()
{
funcArg ptr_, *ptr = &ptr_;
ptr->state = start;
// ptr->extra_data = 0; // optional
while (ptr->state != NULL)
{
ptr->state(ptr);
}
return 0;
}
void start (funcArg *ptr)
{
ptr->state = task1;
}
void stop (funcArg *ptr)
{
ptr->state = NULL;
}
void task1 (funcArg *ptr)
{
ptr->state = stop;
}
uj5u.com熱心網友回復:
這類作品:
#include <stdio.h>
void *a(void)
{
printf("Calling a()\n");
return NULL;
}
void *b(void)
{
printf("Calling b()\n");
return a;
}
void *c(void)
{
printf("Calling c()\n");
return b;
}
int main(void)
{
void *(*funcPtr)(void) = &c;
while (funcPtr) {
funcPtr = funcPtr();
}
}
我并沒有真正看到好的用途,尤其是在將指向函式本身的指標作為引數傳遞時(這就是我為什么省略它的原因),但不管你的船是什么。您當然可以將引數替換為您需要的任何內容。
你可以添加一個 typedef 來幫助一個型別:
typedef void *(*myfunc)(void);
然后您可以執行以下操作:
myfunc funcPtr = &c;
// instead of: void *(*funcPtr)(void) = &c;
我認為這些都不是特別優雅,但應該可以。請注意,您是否將cor分配&c給 myfunc,或者您是否回傳a或&a從其中一個函式回傳都沒有關系。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/480164.html
下一篇:初始化結構指標會導致分段錯誤
