2010-02-09 86 views
4
qsort(bt->rw[t], bt->num[t], 
     sizeof(TRELLIS_ATOM *), 
     (int (*)(const void *,const void *))compare_wid); 

bt->rw[t]是结构指针的指针,bt->[num]int,我不明白,第四个参数是什么,除了compare_wid是某处定义为一个函数如下:这个C qsort函数调用中的参数是什么?

static int compare_wid(TRELLIS_ATOM* a, TRELLIS_ATOM* b) 
{ 
    ... 
    return x; 
} 
+1

写入的代码是错误的。详情请看我的答案。 – 2010-02-09 12:02:16

+0

请参阅接受的问题的答案http://stackoverflow.com/questions/188839/function-pointer-cast-to-different-signature – 2010-02-09 12:10:23

+0

@Alok:所写的代码是非常正确的。没有演员,这将是不正确的。 'compare_wid'衰变到一个指向返回一个整数并带两个指针的函数的指针。就调用代码而言,任何'T *'相当于'void *',并且'const'部分在类型检查之后消失。 – 2010-02-09 12:27:40

回答

5

(int (*)(const void *,const void *))的意思是“处理接下来作为一个函数的指针,该函数接受const void*类型的两个参数并返回int”。 compare_wid确实是一种可以这种方式处理的功能。

qsort将调用此函数在排序时执行项目之间的比较:如果返回的整数为零,则假定项目相等,否则使用整数的符号对它们排序。

+4

'compare_wid()'没有'qsort()'的正确类型。 – 2010-02-09 12:02:45

0

这是一个谓语函数,该函数由qsort实现调用以比较两个TRELLIS_ATOM*

2

第四个参数包含一个显式转换到一个函数指针:

int (*)(const void *,const void *) 
  • int部分对应于返回类型
  • (*)部分是用于一个函数指针
  • 的符号(const void *,const void *)部分是参数类型
3

qsort

void qsort (void * base, size_t num, size_t size, 
        int (* comparator) (const void *, const void *)); 

比较:功能是比较两个 元件。函数应遵循 这个原型:

int comparator(const void * elem1, const void * elem2);

该函数必须接受两个 参数,这些参数指向 元素,类型为void *。这些 参数应该被转换回一些 数据类型并进行比较。

此功能 的返回值应该代表elem1是否是 认为小于,等于,或大于elem2时 更大分别返回, ,负值,零 或正值。

0

这是一个TRELLIS_ATOM类型的元素(无论可能是什么)的自定义排序函数。

compare_wid应该返回的东西< 0,如果*a < *b,> 0,如果*a > *b和0,如果*a*b在逻辑上视为相等。

0

这是一个快速排序函数,它需要一个函数指针指向您的自定义排序处理程序例程。因此,在第四个参数中为函数指针的参数进行类型转换。

当快速排序函数被调用时,它会执行您提供处理排序算法函数指针,即TRELLIS_ATOM *aTRELLIS_ATOM *b,然后你做一个比较检查两者之间,并返回一个1,0,或-1例如逻辑比较:

 
if (*a > *b) return 1; 
if (*a == *b) return 0; 
if (*a < *b) return -1; 

希望这有助于 最好的问候, 汤姆。

22

我会稍微了解该行的含义,但在此之前,我们来了解一下为什么qsort()需要其所需类型的最终参数。 qsort()是一种可以对任何类型的数据进行排序的函数。

你给它提供:

  • 一个基指针,它指向数据的连续块的开始,
  • 在块元素的数目,
  • 一个数据的大小成员,并且
  • 一个比较两个数据值的函数。

由于排序算法通常不依赖于排序数据的类型,因此可以在不知道排序数据类型的情况下编写qsort()。但要能做到这一点,qsort()需要void *参数,这意味着“通用指针”中C.

比方说,你有无序int值的数组:

#define N 1024 
int data[N] = { 10, 2, 3, -1, ... } /* 1024 values */ 

然后你就可以对它们进行排序主叫qsort()

qsort(data, N, sizeof data[0], compare_int); 

dataint *类型传递给qsort()时,并且所述第一parame ter的qsort()void *的类型。由于任何对象指针都可以在C中转换为void *,所以这是可以的。接下来的两个参数也可以。最后一个参数compare_int应该是一个函数,它需要两个const void *参数并返回一个int。该功能将由qsort()调用,其中&data[0]&data[N-1]的指针对数量根据需要多次调用。

将函数声明为f()说:“有两个const void *参数和返回int”:

int f(const void *, const void *); 

如果想声明一个函数指针,我们可以设置为f,指针被声明为:

int (*pf)(const void *, const void *); 
pf = f; 

括号是必需的,否则pf将返回int *函数。现在,pf是指向返回int的函数的指针。

回到我们int排序算法,并从上面,我们可以定义compare_int()为:

int compare_int(const void *a, const void *b) 
{ 
    const int *the_a = a; 
    const int *the_b = b; 
    if (*the_a > *the_b) return 1; 
    else if (*the_a < *the_b) return -1; 
    else return 0; 
} 

在写compare_int(),我们知道,通过指针int *伪装成void *,因此我们将它们转换回到int *,这是好的,然后我们比较这些数字。现在

,我们把关注的代码有问题:

static int compare_wid(TRELLIS_ATOM* a, TRELLIS_ATOM* b) 

意味着compare_wid是一个函数,它有两个TRELLIS_ATOM *参数,并返回一个int。正如我们刚才看到的最后一个参数qsort()应该是一个函数的类型是:

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

即函数接受两个const void *参数和返回int。由于类型不匹配,程序员将compare_wid()转换为qsort()所需的类型。

但是,这有问题。类型的函数:

int (*)(TRELLIS_ATOM *, TRELLIS_ATOM *) 

不等同于类型的函数:

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

,所以它不能保证如果转换会工作。这是更容易,正确,规范申报compare_wid()为:

static int compare_wid(const void *a, const void *b); 

compare_wid()定义应该是这样的:

static int compare_wid(const void *a, const void *b) 
{ 
    const TRELLIS_ATOM *the_a = a; 
    const TRELLIS_ATOM *the_b = b; 
    ... 
    /* Now do what you have to do to compare the_a and the_b */ 
    return x; 
} 

如果你这样做,你将不再需要投在致电qsort(),您的程序不仅会更容易阅读,而且也是正确的。

如果你不能改变compare_wid(),然后写另一个功能:

static int compare_stub(const void *a, const void *b) 
{ 
    return compare_wid(a, b); 
} 

,并呼吁qsort()compare_stub()(不投),而不是compare_wid()

编辑:基于许多错误的答案,这里是一个测试程序:

$ cat qs.c 
#include <stdio.h> 
#include <stdlib.h> 

struct one_int { 
    int num; 
}; 

#ifdef WRONG 
static int compare(const struct one_int *a, const struct one_int *b) 
{ 
#else 
static int compare(const void *a_, const void *b_) 
{ 
    const struct one_int *a = a_; 
    const struct one_int *b = b_; 
#endif 
    if (a->num > b->num) return 1; 
    else if (a->num < b->num) return -1; 
    else return 0; 
} 

int main(void) 
{ 
    struct one_int data[] = { 
     { 42 }, 
     { 1 }, 
     { 100 } 
    }; 
    size_t n = sizeof data/sizeof data[0]; 

    qsort(data, n, sizeof data[0], compare); 
    return 0; 
} 

compare()编译定义为采用两个const struct one_int *值:

$ gcc -DWRONG -ansi -pedantic -W -Wall qs.c 
qs.c: In function `main': 
qs.c:32: warning: passing argument 4 of `qsort' from incompatible pointer type 

用正确的编译定义:

$ gcc -ansi -pedantic -W -Wall qs.c 
$ 

编辑2:对qsort()的最终参数使用compare_wid的合法性似乎存在一些混淆。该comp.lang.c FAQ, question 13.9有一个很好的解释(重点煤矿):

要理解为什么在qsort比较函数的指针好奇的转换是必要的(为什么叫qsort当一个函数指针的投不禁) ,考虑qsort的工作原理很有用。 qsort不知道被排序数据的类型或表示形式:它只是在小块的内存之间进行混洗。 (所有关于块的知识都是它们的大小,您在qsort的第三个参数中指定了它们的大小。)要确定两个块是否需要交换,qsort将调用您的比较函数。 (交换它们,它使用的memcpy等价物。)

由于qsort优惠与未知类型的内存块一个通用的方法,它使用通用指针(void *)引用它们。当qsort调用你的比较函数时,它将两个通用指针作为参数传递给要比较的块。由于它传递了泛型指针,所以你的比较函数必须接受泛型指针,并且在操作它们之前(即在执行比较之前)将指针转换回适当的类型。 A void指针与结构指针的类型不同,在某些机器上它可能具有不同的大小或表示形式(这就是为什么这些类型是正确要求的)。

正如常见问题解答中所述,另请参阅this

+0

+1用于发布此答案的时间和精力。 – Vijay 2010-02-09 12:19:09

+0

很好的答案,但你应该在“compare_int()”中使用“the_a”和“the_b” – groovingandi 2010-02-09 16:26:28

+0

@groovingandi,好眼睛!固定。 – 2010-02-09 17:07:44

0
/* Integer comparison function for use with the stdlib's Qsort. */ 
inline int int_compare(const void *p1, const void *p2) { 
     return (*(int*)p1 - *(int*)p2); 
} 
相关问题