简体   繁体   English

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

[英]How should I understand this iteration function

I am working on porting a C FIFO queue implementation into my code and I don't feel comfortable including functions that I don't understand. 我正在努力将C FIFO队列实现移植到我的代码中,并且我不喜欢包含我不理解的功能。 What does this function do? 此功能有什么作用? I see that it returns an integer value, but I don't know what it means. 我看到它返回一个整数值,但我不知道这意味着什么。 What is the (*iter) parameter? 什么是(*iter)参数? I don't see this type declared in the header or implementation file. 我没有在头文件或实现文件中看到此类型的声明。

You can find the header here 您可以在此处找到标题
You can find the implementation here 您可以在此处找到实现

The function in question is copied below: 有问题的函数复制如下:

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) is a function pointer . int (*iter)(void *data, void *arg)是一个函数指针 When you call fifo_iter , you pass it a callback function in the second parameter. 调用fifo_iter ,您在第二个参数中传递了一个回调函数。 This function must have a signature like: 该函数必须具有如下签名:

int my_callback(void* data, void* arg)

This function will then be called for every item in the fifo_t . 然后, fifo_t每个项目调用此函数。 It will be passed the fn_data member in the data argument. 它将在data参数中传递fn_data成员。 Whatever you pass for arg to fifo_iter will also be passed to iter as his arg argument. 无论您为arg传递给fifo_iter什么, fifo_iter将作为其arg参数传递给iter This is a common way to just pass generic "context" information through to the callback, without having to resort to ugly, thread-unsafe global variables. 这是仅将通用“上下文”信息传递给回调的常见方法,而不必诉诸难看的,线程不安全的全局变量。

So you can use it like this: 因此,您可以像这样使用它:

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

Additionally, we see that it uses the return value of iter in a special way. 此外,我们看到它以特殊方式使用iter的返回值。 First of all, if iter ever returns a negative value, the iteration stops immediately, and fifo_iter returns -1. 首先,如果iter返回负值,则迭代立即停止, fifo_iter返回-1。 This can be an "early failure". 这可能是“早期失败”。 Otherwise, it accumulates the (positive) return values into ret , and then returns that value. 否则,它将(正)返回值累加到ret ,然后返回该值。

Expanding my example. 扩展我的示例。 This assumes that the fifo fn_data members point to strings. 假定fifo fn_data成员指向字符串。 This will count the total number of capital and lowercase letters in all strings in the FIFO, and also return the total length of all strings. 这将计算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);
}

If you take a gander through the Linux kernel source code, you'll see this construct all over the place. 如果您仔细研究Linux内核源代码,那么到处都会看到这种结构。

For a simple FIFO like we have here, it may not seem worth it. 对于像我们这里这样的简单FIFO,似乎不值得。 But when you're dealing with more complex data structures like hash lists, and RCU lists, it makes more sense to maintain the iteration logic in just one place, and utilize callbacks to handle the data in whatever way you need to. 但是,当您处理更复杂的数据结构(例如哈希列表和RCU列表)时,将迭代逻辑仅保留在一个位置并利用回调以所需的任何方式处理数据更为有意义。

It is iterating over the structure, calling the argument function iter() on each element; 它遍历该结构,在每个元素上调用参数函数iter() if an element returns negative, the iteration stops and -1 is returned. 如果元素返回负数,则迭代停止并返回-1。

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

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