有几种明显的使用方法qsort:在比较器中强制转换:
int cmp(const void *v1, const void *v2)
{
const double *d1 = v1, *d2 = v2;
?
}
qsort(p, n, sizeof(double), cmp);
Run Code Online (Sandbox Code Playgroud)
或投射比较器:
int cmp(const double *d1, const double *d2)
{
?
}
qsort(p, n, sizeof(double), (int (*)(const void *, const void *))cmp);
Run Code Online (Sandbox Code Playgroud)
我倾向于使用前者,更多的是出于审美原因。是否有任何技术上的原因偏爱其中一个?
dbu*_*ush 40
您应该避免后一种情况,因为它无效。
两个函数类型要兼容,返回类型必须兼容,对应的参数类型必须兼容。Aconst void *与 a 不兼容,const double *因此函数类型不兼容。通过不兼容的指针类型调用函数会导致未定义的行为。
请注意,仅仅因为可以隐式转换两种类型并不意味着它们是兼容的。以const double *and为例const void *,两种类型之间的转换可以在没有强制转换的情况下进行,但是两种类型的表示不必相同。
这意味着 aconst double *传递给函数的方式可能与 a 传递给函数的方式不同 const void *。因此,通过调用类型int (*)(const double*, const double*)为type 的函数,就好像它具有 type 一样int (*)(const void*, const void*),参数可能会以不正确的方式传递。
虽然 x64 和 ARM 系统通常会为所有指针类型使用相同的表示,但您可能会避免使用前者,但仍然无法保证这一点。现代编译器通常会假设未定义的行为不会发生并基于该事实执行优化。
前一种情况是正确的方法,因为函数的签名与qsort函数期望的兼容。
Nei*_*eil 12
作为附录,还有另一种调用策略qsort:创建一个中间qsort所需的原型函数,该函数调用启用类型的比较函数。
#include <stdlib.h>
#include <stdio.h>
static int double_cmp(const double *d1, const double *d2)
{ return (*d1 > *d2) - (*d2 > *d1); }
static int double_void_cmp(const void *v1, const void *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, &double_void_cmp);
for(i = 0; i < n; i++) printf("%s%.2f", i ? ", " : "", p[i]);
fputs(".\n", stdout);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
虽然这有其自身的问题,但可以double_cmp用作其他非qsort事物的比较器。此外,根据我对ISO 9899 6.3.2.3 的解释,它不需要任何强制转换或显式分配,
指向void的指针可以与指向任何不完整或对象类型的指针相互转换。. . 然后再回来。
除了dbush出色的答案之外,还应该注意的是,具有原型的替代比较函数的情况int cmp(const char *s1, const char *s2),例如strcmp不像问题中的那样明确。C 标准规定:
6.2.5 类型
[...] 指向的指针
void应具有与指向字符类型的指针相同的表示和对齐要求。类似地,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针都应具有相同的表示和对齐要求。所有指向联合类型的指针都应具有相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求。
因此,函数指针与原型int cmp(const void *v1, const void *v2)和int cmp(const char *v1, const char *v2)是不兼容的,但调用序列是不太可能是不同的,甚至在那些极为罕见的目标,其中int cmp(const double *v1, const double *v2)将有问题的(早期的Cray系统和缺乏字节寻址的CPU)。
您没有提供比较函数的代码:简单地返回值的差异 ( *d1 - *d2)是一个常见的错误。这不适用于浮点值,也不适用于int值,因为减法可能会溢出。
这是适用于所有数字类型的递增顺序实现:
int cmp(const void *v1, const void *v2) {
const int *p1 = v1, *p2 = v2;
return (*p1 > *p2) - (*p1 < *p2);
}
Run Code Online (Sandbox Code Playgroud)
对于浮点类型,可能需要对 NaN 值进行特殊处理:
// sort by increasing values, with NaN after numbers
int cmp(const void *v1, const void *v2) {
const double *p1 = v1, *p2 = v2;
if (isnan(*p1)) {
return isnan(*p2) ? 0 : 1;
} else
if (isnan(*p2)) {
return -1;
} else {
return (*p1 > *p2) - (*p1 < *p2);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1062 次 |
| 最近记录: |