qsort函数原型:void qsort(void *base, size_t count, size_t size,
int (*compar)(const void * element1, const void *element2));
compar函数参数可以定义为(const void *)类型,这需要在 compar函数内部cast为所处理类型。如:
1 struct elem{
2 int key;
3 int data;
4 } table[COUNT];
5
6 int key_compare(const void *e1, const void *e2){
7 int v1 = ((struct elem *)e1)->key;
8 int v2 = ((struct elem *)e2)->key;
9 return (v1<v2) ? -1 : ((v1>v2) ? 1 : 0);
10 }
也可以直接定义为所处理类型的指针,在调用qsort函数时需要将compar函数cast为(int (*)(const void *, const void *)。如:
1 int key_compare1(const struct elem *e1, const struct elem *e2){
2 int v1 = e1->key;
3 int v2 = e2->key;
4 return (v1<v2) ? -1 : ((v1>v2) ? 1 : 0);
5 }
6
7 函数调用语句:
8 qsort(table, COUNT, sizeof(struct elem),
9 (int (*)(const void *, const void *))key_compare1);
一开始我以为这样不正确,因为qsort函数内部还是会调用compar的,这样类型就不匹配了啊!
其实是正确的,因为这种类型检查是编译时做的(gcc 使用-c选项)
链接时不做类型检查,只要能找到那个函数名就行;
运行时取参数更不管这些东西了,是用esp+offset直接抓来的。
函数原型是ANSI C才加进来的东西,K&R C第一版中,只要有个函数名就行了。
下面一个小例子,你会看出端倪:
文件:tmp.c
1 #include <stdio.h>
2 int f(void *a, void *b){
3 printf("Call f\n");
4 return 0;
5 }
编译命令: gcc -c tmp.c
文件:main.c
1 int main(){
2 f();
3 return 0;
4 }
编译命令:gcc -c main.c
链接生成可执行文件:gcc tmp.o main.o
执行:
[lym@localhost tmp]$ ./a.out
Call f
一点问题都没有。
nm 看一下符号表:
[lym@localhost tmp]$ nm tmp.o 00000000 T f U puts [lym@localhost tmp]$ nm main.o U f 00000000 T main [lym@localhost tmp]$ nm a.out 080483b4 T f 080483d0 T main U puts@@GLIBC_2.0