C 函数指针 - 未分配但仍然有效。有默认行为吗?

C Function pointer - not assigned but still works. Is there default behavior?

我从一位高素质的讲师给我的程序中获得了这段代码。注意下面的函数指针 cmpfn。它用作比较运算符。我阅读了一些函数指针,它们很有意义。但是,在这个代码库中的任何地方,我都没有看到它被分配给了一个实际定义的函数,就像我在网上阅读的教程中看到的那样。它从未在任何地方定义和分配,但它似乎可以工作。是否有一些默认行为,或者如果不像 cmpfn = &function_defined_elsewhere; 那样分配它,您将如何使它工作?还有为什么他会选择使用这个函数指针而不是直接比较运算符?

/**
 * Find an element in the list
 *
 * cmpfn should return 0 if the comparison to this node's data is equal.
 */
void *llist_find(struct llist *llist, void *data, int (*cmpfn)(void *, void *))
{
    struct llist_node *n = llist->head;

    if (n == NULL) {
        return NULL;
    }

    while (n != NULL) {
        if (cmpfn(data, n->data) == 0) {
            break;
        }

        n = n->next;
    }

    if (n == NULL) {
        return NULL;
    }

    return n->data;
}

编辑(回复反馈):已解决!下面是一般 public edification/curiosity 但现在对我来说很有意义。感谢您的宽容。

我明白了,我需要找到调用此函数的位置。上面的代码在一个名为 llist.h 的文件中,指向函数 (p2f) 的指针在一个名为 hashtable.c 的文件中被调用——实际上是两次。他实际上经常使用 p2f。

这是调用“p2f 托管”函数的一个实例:

/**
 * Get from the hash table with a binary data key
 */
void *hashtable_get_bin(struct hashtable *ht, void *key, int key_size)
{
    int index = ht->hashf(key, key_size, ht->size);

    struct llist *llist = ht->bucket[index];

    struct htent cmpent;
    cmpent.key = key;
    cmpent.key_size = key_size;

    struct htent *n = llist_find(llist, &cmpent, htcmp); // HERE

    if (n == NULL) { return NULL; }

    return n->data;
}

因此正在通过 htcmp。以前我认为你必须将 p2f 分配给带有“=”的函数,但你也可以通过传递给调用函数来完成。今天才知道这些!

这里是 htcmp 的定义:

/**
 * Comparison function for hashtable entries
 */
int htcmp(void *a, void *b)
{
    struct htent *entA = a, *entB = b;

    int size_diff = entB->key_size - entA->key_size;

    if (size_diff) {
        return size_diff;
    }

    return memcmp(entA->key, entB->key, entA->key_size);
}

所以很明显 returns 一个 int,取决于两个 htent(哈希表条目)之间的差异,注意大小差异或调用强大的 memcmp 函数。

这是一个挑战。基础知识是有道理的,但他的代码很忙。我必须在睡梦中巩固它。有如此多的结构和指向函数的指针以及许多其他交互,但它曾经是并且现在仍然是一次很棒的学习体验。

您在此参数中设置了指针。所以,当你调用这个函数时,我会自动自动设置这些指针。所以,我认为你应该看看这个功能的调用。然后你就会得到你问题的答案

void *llist_find(struct llist *llist, void *data, int (*cmpfn)(void *, void *))

当您调用函数 llist_find 时,您应该将引用传递给该函数,该函数必须具有与 llist_find.

预期相同的原型

为了回答您的问题,使用指向函数的指针非常有帮助,尤其是当您使用的结构可以对结构的一个或多个成员执行比较(本例)时。此外,由于该函数使用空指针,您可以使用相同的 llist_find 来处理不同类型结构的列表。