В дополнение к отличному ответу 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 и процессоры, не обладающие байтовой адресацией). .
Вы не предоставляете код для функций сравнения: распространенной ошибкой является простое возвращение разницы значений (*d1 - *d2
). Это не работает для значений с плавающей запятой, а также для значений int
, поскольку вычитание может переполниться.
Вот реализация возрастающего порядка, которая работает для всех типов чисел:
int cmp(const void *v1, const void *v2) {
const int *p1 = v1, *p2 = v2;
return (*p1 > *p2) - (*p1 < *p2);
}
Для типов с плавающей запятой может потребоваться специальная обработка значений 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);
}
}
person
chqrlie
schedule
27.02.2021