我该如何理解这个迭代函数

时间:2014-03-13 22:00:44

标签: c iterator

我正在将C FIFO队列实现移植到我的代码中,我觉得包括我不理解的函数感觉不舒服。这个功能有什么作用?我看到它返回一个整数值,但我不知道它意味着什么。什么是(*iter)参数?我没有在标头或实现文件中看到这种类型。

您可以找到标题here
您可以找到实施here

有问题的功能复制如下:

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);
}

2 个答案:

答案 0 :(得分:4)

int (*iter)(void *data, void *arg)函数指针。当你调用fifo_iter时,你在第二个参数中传递一个回调函数。此功能必须具有以下签名:

int my_callback(void* data, void* arg)

然后将为fifo_t中的每个项目调用此函数。它将在fn_data参数中传递data成员。无论您传递给argfifo_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。