这个C语法是什么意思?

这个C语法是什么意思?,c,syntax,function-pointers,qsort,C,Syntax,Function Pointers,Qsort,这是我正在使用的一个“魔法”数组库 void sort(magic_list *l, int (*compare)(const void **a, const void **b)) { qsort(l->list, l->num_used, sizeof(void*), (int (*)(const void *,const void *))compare); } 我的问题是:qsort的最后一个论点究竟是什么 (int (*)(const void *,

这是我正在使用的一个“魔法”数组库

void
sort(magic_list *l, int (*compare)(const void **a, const void **b))
{
    qsort(l->list, l->num_used, sizeof(void*),
         (int (*)(const void *,const void *))compare);
}
我的问题是:qsort的最后一个论点究竟是什么

(int (*)(const void *, const void*))compare) 

int(*comp_fn)(const void*,const void*)
作为比较器参数,但此排序函数使用带有双指针的比较器。不知何故,上面的一行将双指针版本转换为单指针版本。有人能解释一下吗?

qsort的最后一个参数是将一个接受双指针的函数指针转换为接受qsort的单指针。它只是一个强制转换。

(int(*)(const void*,const void*)compare
是一个C风格的强制转换,用于将函数指针
compare
强制转换为带有两个
const void*
参数的函数指针。

它正在强制转换函数指针。我想原因是,compare可以应用于被取消引用的指针,而不是它们所指向的任何指针。

最后一个参数是函数指针。它指定它接受一个指向返回int的函数的指针,并接受两个
const void**
参数。

这正是您引用的强制转换所做的:它转换类型为的指针

int (*)(const void **, const void **)
指向类型为的指针

int (*)(const void *, const void *)
后者是
qsort
所期望的

在质量差的代码中经常会遇到这样的情况。例如,当有人想要对
int
s数组进行排序时,他们通常会编写一个比较函数,接受指向
int*

int compare_ints(const int *a, const int *b) {
  return (*a > *b) - (*a < *b);
}
这是一种“黑客行为”,导致未定义的行为。显然,这是一种不好的做法。您在示例中看到的只是同一“黑客”的一个不太直接的版本

在这种情况下,正确的方法是将比较函数声明为

int compare_ints(const void *a, const void *b) {
  int a = *(const int *) a;
  int b = *(const int *) b;
  return (a > b) - (a < b);
}

一般来说,如果希望它们的比较函数用作
qsort
(和类似函数)中的比较器,则应使用
const void*
参数来实现它们。

在大多数硬件上,可以假设指针在硬件级别上看起来都相同。例如,在具有平面64位寻址指针的系统中,指针始终是64位整数。指向指针的指针或指向指针的指针指向指向指针的指针也是如此

因此,无论使用什么方法来调用具有两个指针的函数,都将与任何具有两个指针的函数一起工作。指针的具体类型并不重要

qsort
一般地处理指针,好像每个指针都是不透明的。所以它不知道也不关心它们是如何被取消引用的。它知道它们当前的顺序,并使用compare参数计算出它们应该的顺序

您正在使用的库可能保存指向指针的指针列表。它有一个比较函数,可以对两个指针进行比较。因此,它将其转换为qsort。它只是在句法上比,例如

qsort(l->list, l->num_used, sizeof(void*), compare);

/* elsewhere */

int compare(const void *ptr1, const void *ptr2)
{
    // these are really pointers to pointers, so cast them across
    const void **real_ptr1 = (const void **)ptr1;
    const void **real_ptr2 = (const void **)ptr2;

    // do whatever with real_ptr1 and 2 here, e.g.
    return (*real_ptr2)->sort_key - (*real_ptr1)->sort_key;
}

但这似乎很奇怪;为什么不在sort的声明中使用它呢?@Tom因为sort声明中的一个允许你改变指针,这样你就可以在cast中使用它们,这就是为什么它们是双重的pointers@Tom在sort的声明中强制转换它会给函数的用户带来关于强制转换的警告。Tony,说得好,我忽略了仅仅取消引用的便利性&我想cast与sort使用qsort作为实现细节这一事实有关。如果它在sort声明中使用单指针版本,那么它的使用者将必须是调用它时执行强制转换的人。@Tom_Zych,因为调用方可能使用不同类型的args(sort()中的当前arg类型),如果直接传递给qsort()将生成警告/错误。这意味着要用演员阵容来修复每个来电者。这意味着代码很难看。可能compare()函数是遗留代码的一部分。或者呼叫者太多。这是C语法的意思。到底有人该怎么做呢?如果向我展示
sort
函数的原型,并要求我为其编写比较函数,我会将参数转换为
int**
,然后双重取消引用以获得值,这很可能会使程序崩溃。或者给出错误的结果。有些事情看起来很奇怪。compare函数可能最终执行(**a>**b),但qsort将仅使用指向元素的指针调用compare。因此,它可能会多次取消对它的引用。或者数组中的元素可能是指针。排序就是对指针进行排序。在这种情况下,使用typedef会很好。你能再解释一下为什么会出现未定义的行为吗?听起来可能有一个微妙的地方我错过了,这使得包括我的答案都不准确。这不是C语言中未定义的行为,是吗?它是C++的吗?我很感兴趣,你能解释一下吗?@K-ballo:这是C中未定义的行为。Type
int(const void*,const void*)
与Type
int(const int*,const int*)不兼容,这意味着通过强制转换的指针调用函数会导致未定义的行为。@Tommy:仅当函数类型兼容时,才允许将一种函数指针类型转换为另一种,然后通过转换后的值调用函数。兼容性的完整定义见6.7.5.3/15。而且上面的类型不兼容,因为
const int*
const void*
不兼容。程序想要对指针数组进行排序。强制转换可以放在回调函数中:(void*)可以强制转换到任何指针,包括(void**)。这或多或少是一个成员函数,包含std库和magic_列表中的东西之间的粘合逻辑(包括强制转换)。在某些特定的平台上,有很多东西“在硬件级别看起来是一样的”。然而,总的来说,这不是t
qsort(array, n, sizeof *array, compare_ints);
qsort(l->list, l->num_used, sizeof(void*), compare);

/* elsewhere */

int compare(const void *ptr1, const void *ptr2)
{
    // these are really pointers to pointers, so cast them across
    const void **real_ptr1 = (const void **)ptr1;
    const void **real_ptr2 = (const void **)ptr2;

    // do whatever with real_ptr1 and 2 here, e.g.
    return (*real_ptr2)->sort_key - (*real_ptr1)->sort_key;
}