[英]How do I implement callback functions in C?
gcc 4.4.3 c89
我正在創建一個客戶端服務器應用程序,我將需要實現一些回調函數。
但是,我在回調方面沒有太多經驗。 我想知道是否有人知道在設計回調時要遵循的一些好的參考資料。 是否有任何用於c的設計模式。 我確實看過一些模式,但所有的c ++都存在。
非常感謝任何建議,
這是一個非常粗略的例子。 請注意,我唯一要證明的是使用回調,它的設計是信息性的,而不是演示。
讓我們說我們有一個庫(或任何圍繞結構的函數集),我們將看到與此類似的代碼(當然,我將其命名為foo):
typedef struct foo {
int value;
char *text;
} foo_t;
這很簡單。 然后我們(通常)提供一些分配和釋放它的方法,例如:
foo_t *foo_start(void)
{
foo_t *ret = NULL;
ret = (foo_t *)malloc(sizeof(struct foo));
if (ret == NULL)
return NULL;
return ret;
}
接着:
void foo_stop(foo_t *f)
{
if (f != NULL)
free(f);
}
但是我們想要一個回調,所以我們可以定義一個函數,當foo->text
有報告foo->text
時將輸入該函數。 為此,我們使用一個類型化的函數指針:
typedef void (* foo_callback_t)(int level, const char *data);
我們還希望任何foo
系列函數都能夠方便地輸入這個回調。 為此,我們需要將它添加到結構中,現在看起來像這樣:
typedef struct foo {
int value;
char *text;
foo_callback_t callback;
} foo_t;
然后我們編寫實際輸入的函數(使用我們的回調類型的相同原型):
void my_foo_callback(int val, char *data)
{
printf("Val is %d, data is %s\n", val, data == NULL ? "NULL" : data);
}
然后我們需要寫一些方便的方法來說明它實際指向的功能:
void foo_reg_callback(foo_t *f, void *cbfunc)
{
f->callback = cbfunc;
}
然后我們的其他foo函數可以使用它,例如:
int foo_bar(foo_t *f, char *data)
{
if (data == NULL)
f->callback(LOG_ERROR, "data was NULL");
}
請注意,在上面:
f->callback(LOG_ERROR, "data was NULL");
就像這樣做:
my_foo_callback(LOG_ERROR, "data was NULL"):
除此之外,我們通過我們先前設置的函數指針輸入my_foo_callback()
,從而使我們可以靈活地動態定義我們自己的處理程序(甚至可以根據需要切換處理程序)。
回調(甚至上面的代碼)的最大問題之一是使用它們時的類型安全性。 許多回調將采用void *
指針,通常命名為類似context
東西,可以是任何類型的數據/內存。 這提供了很大的靈活性,但如果您的指針遠離您,則可能會出現問題。 例如,您不希望通過賦值意外地將實際的struct *
為char *
(或int
)。 您可以傳遞的不僅僅是簡單的字符串和整數 - 結構,聯合,枚舉等都可以傳遞。 CCAN的類型安全回調可以幫助您在執行此操作時避免不知不覺中的邪惡演員(來自/來自void *
)。
同樣,這是一個過於簡化的示例,旨在向您概述使用回調的一種可能方法。 請考慮它只是作為一個例子的偽代碼。
在C中,回調是通過函數指針完成的。
您絕對需要的一個功能是用戶定義的上下文。 您的代碼采用void *
指針並使其可用於回調函數:
void callback(..., void *ctx);
void call_service_which_invokes_callback(...,
void (*cb)(..., void *ctx),
void *ctx);
這樣,回調可以訪問任何必要的狀態而無需使用全局變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.