以下来自我跟 DeepSeek 的对话:
我要为 C 语言的 qsort 编写一个比较函数,比较两个 uint64_t
,考虑以下两种实现:
int qcmp_uint64(const void* pa, const void* pb) {
uint64_t a = *(uint64_t*)pa;
uint64_t b = *(uint64_t*)pb;
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
int qcmp_uint64_2(const void* pa, const void* pb) {
uint64_t a = *(uint64_t*)pa;
uint64_t b = *(uint64_t*)pb;
return a - b;
}
从直觉上看,似乎第二种实现效率更高,但由于整数相减可能溢出,我对第二种方案的正确性产生了怀疑
第二种方案是否正确?如何高效实现这一比较函数?
对于第二种实现 qcmp_uint64_2
,直接返回 a - b 的确存在隐患。原因如下:
无符号整数减法不会溢出,但结果始终为非负数。
转换为 int 可能导致符号错误:
例如:
高效且安全的实现 利用 比较操作的布尔值隐式转换为 0/1 ,可写出无分支的高效代码:
int qcmp_uint64(const void* pa, const void* pb) {
uint64_t a = *(const uint64_t*)pa;
uint64_t b = *(const uint64_t*)pb;
return (a > b) - (a < b); // 若 a > b 则 1-0=1 ; a < b 则 0-1=-1 ;相等则为 0
}
优点:
性能验证
在 x86-64 架构下,上述代码的典型汇编输出为:
mov rax, [rdi]
cmp [rsi], rax
setb al
seta cl
movzx eax, al
movzx ecx, cl
sub eax, ecx
ret
完全无分支,效率与减法方案相当,且绝对安全。
结论:不要使用 a - b 方案,优先选择无分支的布尔比较实现。
这个 (a > b) - (a < b) 的写法太巧妙了!
感觉这类惯用法( idiom )很难通过看书或网络学习,正是 AI 的强项
只搜到一个相关的: https://stackoverflow.com/questions/3886446/problem-trying-to-use-the-c-qsort-function
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.