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

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Troy Hunt's Blog
Scott Helme
Scott Helme
T
Threat Research - Cisco Blogs
T
Tenable Blog
L
LINUX DO - 热门话题
V
Visual Studio Blog
I
Intezer
Blog — PlanetScale
Blog — PlanetScale
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
Know Your Adversary
Know Your Adversary
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
Netflix TechBlog - Medium
SecWiki News
SecWiki News
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog
Project Zero
Project Zero
W
WeLiveSecurity
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
S
Securelist
Spread Privacy
Spread Privacy
L
LangChain Blog
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
MongoDB | Blog
MongoDB | Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Last Watchdog
The Last Watchdog
Attack and Defense Labs
Attack and Defense Labs
博客园 - 司徒正美
Help Net Security
Help Net Security
L
Lohrmann on Cybersecurity
人人都是产品经理
人人都是产品经理
Forbes - Security
Forbes - Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
博客园 - 【当耐特】
T
Tor Project blog

胡涂说

当心流量别被 Agent 都吃了 当 AI 构建自己 阿嬷 ā mó Bun 要从 Zig 迁移到 Rust ? 好奇心周刊第25期: 如何让AI写好代码 好奇心周刊第24期: 关于AI编程的一些体会和设想 云何降伏其心 好奇心周刊第23期: Claude Code 氛围编程初体验 好奇心周刊第22期: 纳瓦尔谈人生 不确定性世界的生存策略 好奇心周刊第21期: 推理模型的构建与未来 好奇心周刊第20期: 从四个方面了解Palantir 周刊第19期: 一起学习 MCP 周刊第18期: 什么是理工科思维 周刊第17期: 如何构建智能体(Agent) 周刊第16期: Andrej Karpathy 讲 AI 读《毛泽东传》对个人的启发 周刊第15期:Nat Friedman 和 Derek Sivers 的自我介绍 周刊第14期:罗振宇和《罗辑思维》 我看《哪吒》 为什么写作? 心猿意马 从铁幕到硅幕 银弹飞过先锋大厦 从神经网络到 Hugging Face 在大理,听打雷 Git 纪元 凡所有相,皆是虚妄 马斯克的故事与模式 纳瓦尔的智慧 当魔法消失时 人生无论怎么度过都像是浪费 我们都是新穷人 代码、法律和自由软件 乾隆的性格 当下我们还需要启蒙吗? 云门胡饼赵州茶 上海周末骑行:从浦东到外白渡桥 如何选择图书译本? No.13: 周刊的周刊 读书日,推荐些童话和小说 学习邓小平的智慧 自建博客 Nginx 基本配置 给博客换了套新评论系统 我所理解的存在主义 心经说了什么 觉悟之道就是活在当下 巨人的笔记 从零到百亿美金之路 人生如逆旅,我亦是行人 和自己非暴力沟通 听斯蒂芬·金谈写作 行不尽,行不尽,一路青山 周刊第12期:第一次十字军东征 周刊第11期:玄奘之路 周刊第十期:敦煌 周刊第九期:卡片盒笔记法 爸爸是最聪明的 Ruby 编程语言入门 影响人类命运的是什么? 周刊第八期:如何应对公开错误 周刊第七期:如何学习 周刊第六期 周刊第五期 只买书:一个失败的微信小程序产品 改变世界的一次代码提交 如何成为一名黑客 通往开源之路 空山不见人 如何做好演讲 “人生在世,永远也不该演戏作假” 周刊第四期 大卫四岁读的书 宇宙就是一个蛋 周刊第三期 周刊第二期 周刊开刊 阅读开源代码小技巧 英国随记 变成神的动物 人类伟大的时刻 最著名的黑客 《巨婴国》读后 若为自由故 买房记 答案在风中飘 陪产记 自由的代价 谈一谈英语学习 读《霍乱时期的爱情》 简洁 嵌套的梦 四月莎士比亚 七律三首 从明天起,做一个Scrum Master 不能承受的生命之轻 我是丽莎呀 爱美丽、黑暗王子和豌豆公主 诗歌与烟台
重学C语言
胡涂说 · 2019-08-06 · via 胡涂说

多年以后,面对考试题,我会想起开始学习谭浩强《C语言编程》的那个下午。

----《百年C语言》

没想到将近十年没写C语言,最近又拾起来重学了。

自从产品部门(嵌入式)转到系统工程和工具部门后,我基本没再碰过C语言。主要的变成语言转向了 C# 和 Ruby, 偶尔也有 Python. 特别是 Ruby, 从接触学习后的那刻起,我便喜欢上了这个语言。Ruby 的表现力实在是太强了,可以尽情发挥,是我接触过的语言中最接近自然语言表现方式的。特别是在 Ruby on Rails 框架中,加持后的 Rails DSL 写起来效率非常高,往往短短百来行便可以实现一个完整特性的代码。举个例子,要将一个字符串按照;分割成字符串数组,对每个子串转换成全大写,最后将数组去重。这个需求, Ruby 实现起来是什么样子的:

后来在很多语言都增加了闭包特性拥有类似写法时, Ruby 2.0又更近了一步,将上面的语句简化成:

C语言如果想要实现上述功能的话...还是先想想怎么实现一个动态扩容的 char string 吧...像 Ruby 里面的 1.week.ago 2.days.later 这种表现不但能极大的提高编码的生产率,也让写代码变得轻松而快乐。

是的,松本行弘说,他要创造的是让程序员快乐的语言。因此,作为一个从C编程语言转过来的程序员,这种对比太鲜明了,也因此对C语言形成了偏见。毕竟,写C太麻烦了。

但这次是全公司开始搞可信变革,软件工程师需要考试认证,特别是大领导钦点让我们带头体验下考试。没办法,只能扛。考试语言有三种可选:C、C++和 Java, Java 基本没写过,首先排除。C 和 C++ 我偏向于 C++. (我的编程思维倾向于面向对象,面对编程问题我一般首先想到的是如何建模。)但 C++ 也是好久没碰了,加之 C++ 的概念太多,权衡下来决定舍弃,用一两周时间赶紧补补C.

首先要学习C的语言基本知识,除了指针、数组等基本的语法还记得外,很多都忘了。什么字节序、栈、程序段、格式化输出等都重新学起,甚至连 malloc 的写法都不会了。然后是各种数据结构、算法,从链表到队列,从树到图,从 qsort 到 Dijkstra, 逐个补齐。在接下来是编程练习,对程序编译、运行 debug, 这才算拾回了C。

然后我就想,这里面除了C的语法,其他大部分是与C关系不太大的数据结构和算法,以及内存管理等操作系统方面的知识。这十年编程怎么连这些东西都忘了呢。除了业务上对于数据结构和算法并没有太多要求外,还有很大一部分原因是像 Ruby 这种高级语言屏蔽了很多底层的东西,让程序员只需要关系业务抽象即可。Ruby 中 Array 和 Hash 可以覆盖99%场景中的数据结构使用,至于算法也基本都在 API 中提供了,没有的也可以通过 RubyGem 在线 install 下来。至于内存管理等,更是不用操心的事。唯一的不足就是,性能......咳咳。

抛弃C后,我是在面向对象的道路上越走越远。凡事都想着抽象、建模,以至于有些场景会被设计得过于复杂。在刚接触设计模式的那段时间,更是对抽象入魔,无论有没有变化的场景,都要抽象出工厂类来创建对象。真是应了那句老话:手里拿着锤子,看什么都是钉子。

再回头来看C,方觉得C语言简单到质朴,顿时有亲切了许多。与Ruby的简单不同,Ruby 是让人编码时感到简单,用诗句形容即是“楚腰纤细掌中轻”,可以灵活把控。而C给人的感觉是“清水出芙蓉,天然去雕饰。”要真正的理解C,才能用好C,“不可亵玩”,否则将自己给带到坑里了。C就是简单的面向过程的编程语言,用C就是想要扣性能,掌控程序和系统,当然需要很小心的使用。之前有种叫“Modular C”的模块化C编程方法火了一阵,后面貌似较少听说。这种模块封装的思想固然是好的,但有些模式套在C上显得极为复杂;特别是有些实践通过 Struct 中的函数指针来现实C的抽象,把好端端的C语言搞成了四不像。写C就简单的去写,脑子里映射的是系统的实现,而不要过分的强调业务抽象。

因此,这次我在重学C后,开始用C实现一些经典的数据结构和算法。这些代码又让我感受到了C语言的美,虽然这些代码如果用Ruby来实现可能要少一半甚至更多,但无论如何是达不到C语言的极致性能体验的,更重要的是,用C来写程序的过程,就是理解系统的过程。

回到刚才提到的那个问题,如果用C来实现的话,优先考虑的不是像Ruby那样追求代码的极简,而是会追求性能的极简。当然不是说C不关注代码的优雅,对于C而言,算法逻辑是第一位的,所以在循环中总是写++i而不是i++(某些赋值或比较场景除外)1。因此,对于这个问题,C的处理方式可能是先对字符串阶段,利用’;’替换成’\0’的方式截断;转换大小写时对小字母值 - 20(ASCII编码情况下);首尾去空格采用指针偏移的方式;最后去重再用其他数据结构或算法。当然,可能还有其他更好的解法。难怪对C情有独钟的Linus说:“差的程序员关注代码,好的程序员会关注数据结构和它们的关系。”(”Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”)

当然C语言还是有不少缺陷存在,如果不谈面向对象,要说C需要增加或调整哪些特性的话,我觉得最重要的是如下几项:

1、命名空间 命名空间实现起来不难,但我不明白为什么C99乃至C11新标准没有加上。这个特性可以说是影响大型项目的很重要因素,因为没有命名空间,所有的函数名称都是平行的,命名冲突很常见。为了避免这种冲突,只能编程时人为加上很长也很难看的前缀。

2、私有封装 C语言没有 Private 关键字,Struct 所有的成员都是公开的,无法保护内部的数据。而想要实现封装,只能靠声明和实现分离(.h和.c文件)的方式,但这又会来带理解的复杂度。

3、包管理 C++ 也缺少这个功能。虽然Conan等第三方工具提供了 C/C++ 的包管理支持,但到现在为止,仍没有官方或事实标准的包管理。这导致 C/C++ 的组件复用很难做,这也是影响生态的重要因素之一。(JavaScript 这么流行,npm 包管理起了很重要的促进作用。)当然,C/C++编译成二进制码的方式导致了它们使用组件复用也很难,但如果有支持源码复用的统一标准包管理,那么相信C/C++还会增强它们的生命力。而C由于缺乏抽象,可能源码复用也要相对困难些。

我在写一个C的开源库,包含了一些基本的数据结构和算法。这是重新学习的过程,努力向”Good Programmer”前行吧。虽然Ruby等高级语言也可以写算法,但用 Ruby 和用C在思考方式上除了上述不同外,用C更能去理解计算机运行的原理。比如同样是写快速排序,Ruby、Python 等语言就是用几个数组或 list 来存储,不会像C那样用指针偏移的方式来做,用C写快排空间复杂度可达S(1),不需要分配其他内存;而 Ruby 和 Python 才不会管这些呢。

开源C代码库的地址在: hutusi/rethink-c ,Re-Think C, Re-Learn C. 欢迎有兴趣的童鞋一起学习,提 issue 或 PR.

Footnotes

  1. 这里描述不太确切,我是根据《Effective C++》中引述的,但根据StackOverflow上一位网友的描述,并不存在 ++i 性能优于 i++ 的说法。