如何编写适用于整数的C标准库qsort比较函数?
安全实现qsort的有符号整数比较函数
如果你用过C标准库的qsort,大概率见过网上流传的这种整数比较函数示例:
int compare(const void *a, const void *b) { const int *ia = (const int *)a; // 转换指针类型 const int *ib = (const int *)b; return *ia - *ib; }
看起来简洁对吧?但这里藏着个大坑:有符号整数溢出/下溢,这在C里属于未定义行为。举个极端例子:如果*ia是INT_MAX(比如2147483647),*ib是-1,那*ia - *ib就会超出int的范围,程序可能崩溃、输出乱序,甚至出现更诡异的行为——毕竟未定义行为没有任何保障。
很多人可能会想到用更冗长的判断,但其实有既安全又优雅的解决方案:
方案一:直观的分支判断(最易读)
int compare(const void *a, const void *b) { const int *ia = (const int *)a; const int *ib = (const int *)b; if (*ia < *ib) { return -1; } else if (*ia > *ib) { return 1; } return 0; }
这种写法完全不涉及算术运算,通过直接的大小比较返回对应值,从根源上避免了溢出问题。逻辑清晰,哪怕是新手也能一眼看懂,维护起来毫无压力。
方案二:三元表达式简化(简洁且安全)
如果觉得上面的分支有点啰嗦,可以用这个小技巧:
int compare(const void *a, const void *b) { const int *ia = (const int *)a; const int *ib = (const int *)b; return (*ia > *ib) - (*ia < *ib); }
原理很简单:C语言中布尔表达式的结果是1(真)或0(假)。当*ia大于*ib时,(*ia > *ib)是1,(*ia < *ib)是0,相减得1;反之得-1;相等时两者都是0,相减得0。同样完全不会触发溢出,代码也更紧凑。
不管选哪种,都比用减法的危险实现靠谱得多——毕竟在C里,未定义行为是绝对要避免的雷区。
内容的提问来源于stack exchange,提问作者balki
相关产品推荐
相关产品推荐

