繁体   English   中英

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

[英]How should I understand this iteration function

我正在努力将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);
}

int (*iter)(void *data, void *arg)是一个函数指针 调用fifo_iter ,您在第二个参数中传递了一个回调函数。 该函数必须具有如下签名:

int my_callback(void* data, void* arg)

然后, fifo_t每个项目调用此函数。 它将在data参数中传递fn_data成员。 无论您为arg传递给fifo_iter什么, fifo_iter将作为其arg参数传递给iter 这是仅将通用“上下文”信息传递给回调的常见方法,而不必诉诸难看的,线程不安全的全局变量。

因此,您可以像这样使用它:

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列表)时,将迭代逻辑仅保留在一个位置并利用回调以所需的任何方式处理数据更为有意义。

它遍历该结构,在每个元素上调用参数函数iter() 如果元素返回负数,则迭代停止并返回-1。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM