惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy International News Feed
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Spread Privacy
Spread Privacy
The Hacker News
The Hacker News
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
Google Online Security Blog
Google Online Security Blog
H
Heimdal Security Blog
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 【当耐特】
Webroot Blog
Webroot Blog
小众软件
小众软件
Help Net Security
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
Cloudbric
Cloudbric
AI
AI
WordPress大学
WordPress大学
博客园 - 聂微东
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
Hacker News: Ask HN
Hacker News: Ask HN
H
Hacker News: Front Page
博客园 - Franky
V
V2EX
Schneier on Security
Schneier on Security
G
GRAHAM CLULEY
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
H
Help Net Security
量子位
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recorded Future
Recorded Future
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
C
Cisco Blogs
S
Security Affairs

C

各位大佬, C 語言該怎麼練習啊 - V2EX 分享一个代码优化导致的死循环 - V2EX 人再笨还能写不出内存安全的 C? - V2EX 想念 C - V2EX C11 的 _Generic,现实当中用得多不多?(尤其是公司项目) 坑爹的 GBK:大家都应该去用 UTF-8 - V2EX 一个简单的 C 程序,但是不明白区别在哪里 我这段 C 代码可以在编译时候输出结构体的大小,你们还有什么好点子, show me the code! - V2EX 这段话是否正确?「取余这个运算,只有 Python 是对的。当初 C 这个老师教错了,那么一大票学生也就只敢跟着老师错。只有 Python 敢于站出来坚持正确答案。」 - V2EX C 中可变参数如何直接传递到 printf() - V2EX C 的内存打印实现 - V2EX 函数能否实现透传不定长度参数,最终由 printf 打印 请大佬帮忙修改一份 elf 文件里的数值 - V2EX Linux 上 C 的程序遇到个异常退出问题,局部变量大小有限制?? C 语言新手求助:如何在 vscode 中使用第三方库? - V2EX 将资源嵌入到可执行文件中并保持目录结构 - V2EX 一个简单实用的 C 工程示例, 附简洁的 Makefile - V2EX 关于 C 语言的相关问题 - V2EX 轮子更新: C/C++ 跨平台小工具库 - V2EX 为什么下列程序进行的是无符号乘法? - V2EX 用 riscv64- Linux -gnu-gcc 编译的 c 文件为啥能在 x8664 下运行? - V2EX char *s = "0123"和 char s[] = "0123"的区别 有人能完整地解释一下 int (*daytab) [13]和 int *daytab[13]吗 在 c 语言中, int a;是 declaration 还是 definition - V2EX 一个简单(奇怪)的 C 语言问题 - V2EX c 语言中打印指针的值打印的是 OS 分配的虚拟地址的值吗?要怎么知道 OS 给这个 c 程序进程分配的虚拟地址的大小呢? - V2EX gcc 是怎么找到 system 函数的定义(实现)的? - V2EX 用 C 实现轻量级表达式完成策略定制化和模板内容生成 - V2EX c 语言是如何给汉字编码的? - V2EX 还是不太理解 C 静态库和动态库? - V2EX 开源 C 库 bfdev: MPI 大数运算 - V2EX C 语言中的面向切面编程(AOP) - V2EX 网络语言污染/扭曲专业术语名词——《为什么 c 语言这么抽象?》 - V2EX C 语言函数资源开销可观测性 - V2EX C 语言用户态函数可观测性 - V2EX 在 C 中,如何正确拷贝字符串 - V2EX c 语言中自定义 section 段问题请教 - V2EX C 语言的源码过滤功能的工具 - V2EX 求助 libcurl 的 curl_easy_pause() 使用方法 - V2EX 各位有什么深入了解 C 语言的书嘛? - V2EX 不熟悉 cmake,请教一下多模块项目的 cmake 写法 - V2EX 大家有没有值得推荐的 c 语言的开源项目,用来学习或者贡献的。 - V2EX 求帮忙看一下这个 C 代码为什么会段错误! - V2EX int 型返回值所能表达的内容极限 - V2EX 刚刚突然感受到了 C 语言指针的神奇之处 - V2EX 开源 C 语言库 Melon 之模块选择性编译 - V2EX 这年头搞 c 还有前途吗 看看我的 leetcode 第 151 题目 反转字符串 - V2EX 百变开源 C 语言库日志模块 - V2EX 最好用的 C 语言 JSON 解析器 - V2EX
分享一个用 AI 学习 C 语言的例子
henix · 2025-04-24 · via C

以下来自我跟 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;
}

从直觉上看,似乎第二种实现效率更高,但由于整数相减可能溢出,我对第二种方案的正确性产生了怀疑

第二种方案是否正确?如何高效实现这一比较函数?

DeepSeek 回答

对于第二种实现 qcmp_uint64_2,直接返回 a - b 的确存在隐患。原因如下:

  1. 无符号整数减法不会溢出,但结果始终为非负数。

    • 当 a < b 时,a - b 会得到一个极大的无符号值(模运算结果),例如 1 - 2 = UINT64_MAX 。
  2. 转换为 int 可能导致符号错误:

    • 若 a - b 的值超过 INT_MAX ,转换为 int 时会触发实现定义行为(通常为截断高位,导致结果为负数)。此时 qsort 会误判 a < b ,造成排序错误。

例如:

  • 若 a = 1, b = 2 ,则 a - b = UINT64_MAX 。
  • 转换为 int 时,假设 int 为 32 位,结果为 -1 (正确)。
  • 但若 a = 0x80000000, b = 0 ,在 32 位 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
}

优点:

  • 完全避免溢出风险:不依赖数值运算,仅用比较结果。
  • 无分支:现代编译器(如 GCC/Clang )会将其优化为无跳转指令,性能与 a - b 相近。
  • 代码简洁:符合严格比较逻辑。

性能验证

在 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