2014-03-13 15 views
0

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

回答

4

int (*iter)(void *data, void *arg)函数指针。当您拨打fifo_iter时,您会在第二个参数中传递一个回调函数。此功能必须有一个签名,如:

int my_callback(void* data, void* arg) 

此功能将被要求在fifo_t每一个项目。它将通过data参数中的fn_data成员。无论您通过的是arg还是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列表时,将迭代逻辑保持在一个地方更合理,并且可以使用回调来以任何需要的方式处理数据。

+0

你好。我试图将int变量添加到此fifo。但我只能看到相同的var(这是最后一个var)for(int i = 0; i <4; i ++)int * k = malloc(sizeof(int)); * k = rand(); fifo_add(ff,k); free(k); } fifo_iter(ff,my_callback,NULL); – Max

+1

@garrydvaraza如果您有新问题,请提出新问题。评论是不正确的地方。 –

0

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

相关问题