简体   繁体   中英

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. 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? 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 . When you call fifo_iter , you pass it a callback function in the second parameter. 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 . It will be passed the fn_data member in the data argument. Whatever you pass for arg to fifo_iter will also be passed to iter as his arg argument. 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. First of all, if iter ever returns a negative value, the iteration stops immediately, and fifo_iter returns -1. This can be an "early failure". Otherwise, it accumulates the (positive) return values into ret , and then returns that value.

Expanding my example. This assumes that the fifo fn_data members point to strings. 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.

// 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.

For a simple FIFO like we have here, it may not seem worth it. 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.

It is iterating over the structure, calling the argument function iter() on each element; if an element returns negative, the iteration stops and -1 is returned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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