我正在将C FIFO队列实现移植到我的代码中,我觉得包括我不理解的函数感觉不舒服。这个功能有什么作用?我看到它返回一个整数值,但我不知道它意味着什么。什么是(*iter)
参数?我没有在标头或实现文件中看到这种类型。
有问题的功能复制如下:
int fifo_iter(fifo_t *f, int (*iter)(void *data, void *arg), void *arg)
{
fifonode_t *fn;
int rc;
int ret = 0;
for (fn = f->f_head; fn; fn = fn->fn_next) {
if ((rc = iter(fn->fn_data, arg)) < 0)
return (-1);
ret += rc;
}
return (ret);
}
答案 0 :(得分:4)
int (*iter)(void *data, void *arg)
是函数指针。当你调用fifo_iter
时,你在第二个参数中传递一个回调函数。此功能必须具有以下签名:
int my_callback(void* data, void* arg)
然后将为fifo_t
中的每个项目调用此函数。它将在fn_data
参数中传递data
成员。无论您传递给arg
到fifo_iter
的是什么,也会作为iter
参数传递给arg
。这是将通用“上下文”信息传递给回调的常用方法,而不必诉诸丑陋的线程不安全的全局变量。
所以你可以像这样使用它:
int my_callback(void* data, void* arg) {
printf("my_callback(%p, %p)\n", data, arg);
return 0; // always continue
}
void test(void) {
fifo_t myfifo; // Needs initialized and populated...
fifo_iter(&myfifo, my_callback, NULL);
}
此外,我们发现它以特殊方式使用iter
的返回值。首先,如果iter
返回负值,则迭代立即停止,fifo_iter
返回-1。这可能是“早期失败”。否则,它会将(正)返回值累积到ret
中,然后返回该值。
扩展我的榜样。这假设fifo fn_data
成员指向字符串。这将计算FIFO中所有字符串中的大写和小写字母总数,并返回所有字符串的总长度。
// The context that we'll maintain during the iteration
struct my_context {
int caps;
int lowers;
};
// The callback function, called for every string in the FIFO.
int my_callback(void* data, void* arg) {
const char* str = data; // Node data is a string
struct my_context *ctx = arg; // Arg is my context
// If any string in the FIFO has a !, abort immediately.
if (strchr(str, '!'))
return -1;
// Update the context to include the counts for this string
ctx->caps += count_capital_letters(str);
ctx->lowers += count_lowercase_letters(str);
// fifo_iter will accumulate this length
return strlen(str);
}
// Test driver function
void test(void) {
fifo_t myfifo;
struct my_context ctx;
int total;
// Assuming these functions exist:
fifo_init(&myfifo);
fifo_append(&myfifo, "Stack");
fifo_append(&myfifo, "Overflow");
// Initialize the context
ctx.caps = 0;
ctx.lowers = 0;
// Iterate over myfifo, passing it a pointer to the context
total = fifo_iter(&myfifo, my_callback, &ctx);
if (total < 0) {
// Any string had a '!'
printf("Iteration failed!\n");
return;
}
printf("total=%d caps=%d lowers=%d \n", total, ctx.caps, ctx.lowers);
}
如果您了解Linux内核源代码,您将会看到这个构造。
对于像我们这样的简单FIFO,它似乎不值得。但是,当您处理更复杂的数据结构(如散列列表和RCU列表)时,将迭代逻辑维护在一个位置更有意义,并利用回调以您需要的任何方式处理数据
答案 1 :(得分:0)
它遍历结构,在每个元素上调用参数函数iter()
;如果元素返回负数,则迭代停止并返回-1。