浅谈C语言自定义比较函数

在使用C语言比较函数qsort的时候需要自己编写比较函数,比如两个参数ab,很多人对于return a - b就是升序,return b - a就是降序感到不理解,这篇文章可以快速解决一下这个问题。

qsort不感知你到底是升序还是降序,他完全根据参数的返回值来决定先后顺序,同样两个参数ab

  • 返回值 < 0:表示a应该排在b前面
  • 返回值 == 0:表示ab相等,他们的相对顺序不确定
  • 返回值 > 0:表示a应该排在b后面

对于整数ab,目标为升序排序(从小到大):

  • a > b,我们希望a排在b的后面,也就是希望返回值为正
  • a < b,我们希望a排在b的前面,也就是希望返回值为负

所以最直接的方法就是return (a - b),可以完美覆盖我们的希望,对着上面不等式,简单的把b移到不等式左边即可:

  • a < b -> 希望a排前 -> 希望返回负数 -> a - b < 0 -> 正确!
  • a > b -> 希望a排后 -> 希望返回正数 -> a - b > 0 -> 正确!

但这样的做法没有考虑到整数溢出的问题。

例如,比较两个int类型的值:

  • a = INT_MAX(2147483647)
  • b = -1
  • a - b = 2147483647 - (-1) = 2147483648

这个结果超出了int型正数的最大值,会发生溢出,导致结果是未定义行为,很可能变成一个负数。这会导致排序结果完全错误。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <limits.h>
#include <stdio.h>

int cmp1(const void *a, const void *b) {
    int iA = *(int *)a;
    int iB = *(int *)b;
    if (iA < iB)
        return -1;
    else if (iA > iB)
        return 1;
    else
        return 0;
}

int cmp2(const void *a, const void *b) { return *(int *)a - *(int *)b; }

int main() {
    int arr1[] = {INT_MAX, -1, 1, 3, 2, INT_MIN, 4, 0};
    int arr2[] = {INT_MAX, -1, 1, 3, 2, INT_MIN, 4, 0};
    
    qsort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp1);
    for (size_t i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++) {
        printf("%d ", arr1[i]);
    }

    printf("\n");

    qsort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp2);
    for (size_t i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++) {
        printf("%d ", arr2[i]);
    }
    return 0;
}
1
2
3
输出结果:
-2147483648 -1 0 1 2 3 4 2147483647 
-1 0 1 2 3 4 2147483647 -2147483648
updatedupdated2025-09-072025-09-07