这个 C 语法是什么意思?

发布于 2024-12-03 22:24:35 字数 545 浏览 3 评论 0原文

这是来自我正在使用的“神奇”数组库。

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) 

qsort 采用 int (*comp_fn)(const void *,const void *) 因为它是比较器参数,但此排序函数采用带有双指针的比较器。不知何故,上面的行将双指针版本转换为单指针版本。有人可以帮忙解释一下吗?

This is from a 'magic' array library that I'm using.

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

My question is: what on earth is the last argument to qsort doing?

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

qsort takes int (*comp_fn)(const void *,const void *) as it's comparator argument, but this sort function takes a comparator with double pointers. Somehow, the line above converts the double pointer version to a single pointer version. Can someone help explain?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

提笔书几行 2024-12-10 22:24:35

这正是您引用的强制转换的作用:它将类型的指针转​​换

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

为类型的指针,

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

后者是 qsort 所期望的。

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

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

,并且当需要实际调用 >qsort 他们强制将其转换为正确的类型以抑制编译器的抱怨

qsort(array, n, sizeof *array, (int (*)(const void *,const void *)) compare_ints);

这是一种“黑客”,会导致未定义的行为。显然,这是一种不好的做法。您在示例中看到的只是同一“黑客”的不太直接的版本。

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

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(array, n, sizeof *array, compare_ints);

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

That's exactly what the cast you quoted does: it converts a pointer of type

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

to a pointer of type

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

The latter is what is expected by qsort.

Thing like this are encountered rather often in bad quality code. For example, when someone wants to sort an array of ints, they often write a comparison function that accepts pointers to int *

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

and when the time comes to actually call qsort they forcefully cast it to the proper type to suppress the compiler's complaints

qsort(array, n, sizeof *array, (int (*)(const void *,const void *)) compare_ints);

This is a "hack", which leads to undefined behavior. It is, obviously, a bad practice. What you see in your example is just a less direct version of the same "hack".

The proper approach in such cases would be to declare the comparison function as

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

and then use it without any casts

qsort(array, n, sizeof *array, compare_ints);

In general, if one expects their comparison functions to be used as comparators in qsort (and similar functions), one should implemnent them with const void * parameters.

何处潇湘 2024-12-10 22:24:35

qsort 的最后一个参数是将采用双指针的函数指针转换为采用 qsort 将接受的单指针的函数指针。这只是一个演员阵容。

The last argument to qsort is casting a function pointer taking double pointers, to one taking single pointers that qsort will accept. It's simply a cast.

凉墨 2024-12-10 22:24:35

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

因此,无论使用什么方法来调用带有两个指针的函数,都适用于任何带有两个指针的函数。指针的具体类型并不重要。

qsort 一般地对待指针,就好像每个指针都是不透明的一样。所以它不知道也不关心它们是如何取消引用的。它知道它们当前的顺序,并使用比较参数来计算出它们应该采用的顺序。

您使用的库大概保留了指向指针的指针列表。它有一个比较函数,可以比较两个指针与指针。因此它会将其传递给 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;
}

On most hardware you can assume that pointers all look the same at the hardware level. For example, in a system with flat 64bit addressing pointers will always be a 64bit integer quantity. The same is true of pointers to pointers or pointers to pointers to pointers to pointers.

Therefore, whatever method is used to invoke a function with two pointers will work with any function that takes two pointers. The specific type of the pointers doesn't matter.

qsort treats pointers generically, as though each is opaque. So it doesn't know or care how they're dereferenced. It knows what order they're currently in and uses the compare argument to work out what order they should be in.

The library you're using presumably keeps lists of pointers to pointers about. It has a compare function that can compare two pointers to pointers. So it casts that across to pass to qsort. It's just syntactically nicer than, e.g.

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;
}
站稳脚跟 2024-12-10 22:24:35

它正在转换一个函数指针。我想原因是比较可以应用于取消引用的指针,而不是它们指向的任何指针。

It is casting a function pointer. I imagine that the reason is so that compare can be applied to the pointers that are dereferenced rather than whatever they are pointing to.

眼眸里的快感 2024-12-10 22:24:35

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

(int (*)(const void *,const void *))compare is a C style cast to cast the function pointer compare to a function pointer with two const void * args.

烟燃烟灭 2024-12-10 22:24:35

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

The last argument is a function pointer. It specifies that it takes a pointer to a function that returns an int and takes two const void ** arguments.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文