qsort:转换比较器函数本身还是比较器函数体中的参数?

2021-02-28 18:20

在c中使用qsort:cast有两种明显的方法操作员:int cmp(const void*v1,const void*v2){const double*d1=v1,*d2=v2;:}qsort(p,n,sizeof(double),cmp)

解答动态

  • 应避免后一种情况,因为它无效。
    要使两个函数类型兼容,返回类型必须兼容,相应的参数类型必须兼容。const void*与const double*不兼容,因此函数类型不兼容。通过不兼容的指针类型调用函数会导致未定义的行为。请注意,仅仅因为两个类型可以隐式转换,并不意味着它们是兼容的。以const double*和const void*为例,这两种类型之间的转换可以在没有强制转换的情况下执行,但是这两种类型的表示形式不必相同。
    这意味着const double*传递给函数的方式可能不同于const void*传递给函数的方式。因此,通过调用int(*)(const double*,const double*)类型的函数,就像调用int(*)(const void*,const void*)类型的函数一样,参数可能会以错误的方式传递。
    x64和ARM系统通常会对所有指针类型使用相同的表示形式,但您可以不使用前者,但这仍然无法保证。现代编译器通常会假定不发生未定义的行为,并基于此事实执行优化。
    前一种情况是正确的方法,因为函数的签名与qsort函数所期望的兼容。

    • 作为附录,调用qsort还有另一种策略:创建一个中介qsort所需的原型函数,该原型函数调用启用类型的比较函数。
      #includegt;#includegt;static int double\u cmp(const double*d1,const double*d2){return(*d1gt;*d1);}static int double\u void\u cmp(const void*v1,constvoid*v2){return double_cmp(v1,v2);}int main(void){double p[]={2.18,6.28,3.14,1.20,2.72,0.58,4.67,0.0,1,1.68};const size_t n=sizeof p/sizeof*p;size_t i;qsort(p,n,sizeof*p,lt;n;i++)printf(quot;,i?quot;:quot;\n";,stdout);return EXIT_SUCCESS;} 尽管这有它自己的问题,但是可以使用double_cmp作为其他非qsort事物的比较。而且,它不需要任何强制转换或显式赋值,根据我对iso98996.3.2.3的解释,
      A指向void的指针可以转换为或从指向任何不完整或对象类型的指针。

      • 除了dbush极好的答案之外,还应该注意比较函数不应该简单地返回值的差(*d1-*d2)。这不适用于浮点值,也不适用于int值,因为减法可能会溢出。
        这里有一个递增顺序的实现,适用于所有数字类型:
        int cmp(const void*v1,const void*v2){const int* =v1,*
        =v2;对于浮点类型,返回(* lt;*
        );} ,可能需要对NaN值进行特殊处理需要:
        //按递增值排序,在numbersint cmp(const void*v1,const void*v2){const double* =v1,*
        =v2;if(isnan(* )){返回isnan(*
        )?0:1;}else if(isnan(*
        )){return-1;}else{return(* lt;*
        );}}

        • End

        免责声明:

        本页内容仅代表作者本人意见,若因此产生任何纠纷由作者本人负责,概与琴岛网公司无关。本页内容仅供参考,请您根据自身实际情况谨慎操作。尤其涉及您或第三方利益等事项,请咨询专业人士处理。