IT技术博客大学习 共学习 共进步

标签:C Language

共 3 篇相关文章

IT 累计浏览 2,520

vfork 挂掉的一个问题

这篇讲的是 vfork 系统调用中一个经典的“坑”:为什么在子进程中使用 `return` 会导致程序崩溃,而用 `exit()` 却不会?作者从知乎上的一个实际提问出发,澄清了一些可能误导人的回答。 文章首先梳理了 fork 与 vfork 的根本区别——fork 会复制父进程内存,而 vfork 则让父子进程共享同一内存空间。vfork 的设计初衷是为了在创建子进程后立即执行 exec 时提高效率。关键点在于,vfork 保证子进程先运行,直到它调用 `exit()` 或 `exec()` 后,父进程才继续。 崩溃的根源正在于此:因为父子进程共享栈空间,如果在子进程的 main 函数中使用 `return`,它会像正常函数返回一样修改栈(弹栈、释放局部变量),这相当于破坏了父进程正在使用的栈。当父进程稍后恢复执行时,栈已被改写,导致不可预知的行为或直接崩溃。而 `exit()` 是直接终止进程,不会去操作和释放共享的函数栈,因此父进程能安全恢复。 文章最后也指出,现代操作系统已通过“写时拷贝”技术大幅优化了 fork,使得 vfork 的性能优势不再明显,Linux 手册也不鼓励使用它,除非对性能有极致要求。理解这个底层机制,有助于我们避免这类隐蔽的陷阱。

IT 累计浏览 13,162

Linus:利用二级指针删除单向链表

这篇讲的是Linus Torvalds如何用二级指针来优雅地删除单向链表节点。文章从Linus在slashdot上对一段“标准”代码的批评切入,他直言那种需要维护`prev`指针并判断是否为表头的写法,表明作者“不懂指针”。 核心对比了两种实现思路。传统写法(很多教科书和面试题的标准答案)需要额外维护一个`prev`指针,并在删除时判断当前节点是否为链表头,代码中存在条件分支。而Linus推崇的“core low-level coding”技巧,是直接使用一个指向节点指针的指针(即二级指针`node** curr`)来遍历和操作链表。其精妙之处在于,无论要删除的是表头还是中间节点,都可以通过统一的`*curr = entry->next`操作完成,无需任何条件判断。文章通过逐行代码解析和示意图,阐明了这种写法如何将“前驱指针”的概念融入到对`next`指针本身的间接操作中,最终生成更清晰、更可能被编译器优化出高效指令的代码。 这种对指针的深刻理解和运用,体现了Linus所看重的注重细节、追求高效底层编码的审美。

IT 累计浏览 2,280

从数组里删除一个元素

这篇讲的是数组元素删除这个看似基础实则充满陷阱的操作。作者没有停留在某个特定语言的语法教学上,而是横向对比了 JavaScript 的 `splice`、Python 的列表推导式以及 Java 中 `ArrayList.remove()` 等多种主流方案。他详细拆解了每种方法背后的内存移动机制与性能开销,比如为什么基于索引的删除在连续内存的数组上效率更高,而链表结构的列表删除则更灵活。 文章特别点出了初学者常忽略的细节:例如在循环中删除元素时容易引发的索引错位问题,以及某些语言中“删除”操作实际上只是标记为不可用、等待后续垃圾回收的特性。作者通过具体的代码片段和执行流程分析,让这些抽象概念变得清晰。 对于需要频繁进行增删操作的数据结构选型,文章给出了明确建议:如果追求极致读取速度且删除不频繁,连续数组更优;若需动态增删,则应考虑链表或特定优化过的容器。整个对比基于实际的代码执行和性能考量,最终指向一个核心:理解底层机制,才能做出明智的技术选择。