如何在C语言的TAILQ中添加函数指针
问题分析与解决
你的代码核心问题出在函数指针的处理上,完全没必要用calloc分配内存再memcpy——函数指针本身就是一个存储函数地址的变量,直接赋值就行。另外代码里还有两个低级错误,一起给你修正:
错误点拆解
- 函数指针的错误操作:你给
entry->callback分配堆内存,再把函数指针的值拷贝进去,这会让entry->callback指向一块堆内存,而不是目标函数的地址,触发回调时必然出错。 - 结构体成员访问错误:
main里的TAILQ_INIT(&identifier->callback_list)是错的,identifier是全局结构体变量,不是指针,应该用.访问成员,改成TAILQ_INIT(&identifier.callback_list)。 - 关键字冲突:
register是C语言的关键字,不能用作函数名,得改成register_callback之类的合法名称。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/queue.h> // 确保包含TAILQ的头文件 #define OK 0 #define NOK -1 #define errorf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #define debugf(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) #define FREE(ptr) do { if (ptr) free(ptr); ptr = NULL; } while(0) struct callback_list_entry { int (*callback)(void *, unsigned int); char *title; TAILQ_ENTRY(callback_list_entry) entries; }; TAILQ_HEAD(callback_list, callback_list_entry); struct sipc_identifier { unsigned int port; int (*broadcast_callback)(void *, unsigned int); struct callback_list callback_list; }; typedef struct sipc_identifier _sipc_identifier; static _sipc_identifier identifier; int my_callback(void *prm, unsigned int len) { printf("here is %s: %s len: %d\n", __func__, (char *)prm, len); return OK; } static int add_callback_to_callback_list(int (*callback)(void *, unsigned int), char *title, _sipc_identifier *identifier) { struct callback_list_entry *entry = NULL; if (!callback || !identifier || !title) { // 补充title的空指针检查 errorf("args cannot be NULL\n"); return NOK; } entry = calloc(1, sizeof(struct callback_list_entry)); if (!entry) { errorf("calloc failed\n"); return NOK; } // 直接赋值函数指针,无需分配内存和memcpy entry->callback = callback; debugf("callback address: %p, entry->callback: %p\n", callback, entry->callback); // title的处理是对的,继续保留 entry->title = calloc(1, strlen(title) + 1); if (!entry->title) { errorf("calloc failed\n"); FREE(entry); return NOK; } strcpy(entry->title, title); TAILQ_INSERT_HEAD(&identifier->callback_list, entry, entries); return OK; } // 把register改成register_callback,避免关键字冲突 static int register_callback(char *title, int (*callback)(void *, unsigned int)) { if (!title || !callback) { errorf("args cannot be NULL\n"); return NOK; } return add_callback_to_callback_list(callback, title, &identifier); } int main(int argc, char **argv) { // 修正结构体成员访问方式,用.而不是-> TAILQ_INIT(&identifier.callback_list); register_callback("App_A_Registered_title", my_callback); // 函数名本身就是指针,无需& // 可以加个测试触发回调的代码验证 struct callback_list_entry *entry = TAILQ_FIRST(&identifier.callback_list); if (entry) { char test_data[] = "test callback"; entry->callback(test_data, strlen(test_data)); } return OK; }
关键修改说明
- 函数指针赋值:直接
entry->callback = callback;即可,函数指针和普通指针一样,赋值就能传递地址,不需要额外内存分配。 - 修正结构体访问:全局变量
identifier是实体,用.访问成员,指针才用->。 - 关键字重命名:把
register函数改成register_callback,规避C语言关键字冲突。 - 补充空指针检查:在
add_callback_to_callback_list里加了title的空指针判断,更严谨。
测试这段代码,回调函数能正常触发输出,TAILQ的存储和访问也没问题。
内容的提问来源于stack exchange,提问作者dogus yuksel
相关产品推荐
相关产品推荐

