之前在知乎看见一个问题,问为什么还有985高校给大一上 C 语言课,如下:
不过这个提问方式未免有引战嫌疑,所以被知乎管理员编辑为如下问题:
这样显然中立很多了,是在摆事实提问题。
接下来我们就聊聊 985 大学为什么还是给大一上 C 语言课。
首先,我们学的是 Computer Science,而不是 Programming Language,语言真的真的真的不是重点。
语言只是工具,工具没有优劣,只有各自适用的场景不同。
所以,以下所有讨论皆不涉及语言优劣,一切论述以怎样才是有利于学好 Computer Science 为原则(求生欲满满
大学教育,尤其是 985、211 这种国内最顶尖的一批高校,应该注重通识教育而不是专项教育,在专业上更要注重基础、底层、偏向原理。
只有掌握了最核心的东西,学起那些偏技能的东西才会很快很轻松。
我记得当时大二需要写爬虫,大概看了一天左右的 Python 教程,会基本的循环、判断、控制流、一些 builtin 函数和类,然后学了下 requests 库就直接开干了。
其实像 JS、Python、Node、PHP 这些东西,科班学生几乎都是自学,哪还用得上单独开一门课呀。
自学是最基本的要求,需要用到的时候自己去看教程、文档,直接就上手写了。
所以这种语言完全没必要开一学期的课来学,倒是非常适合放在计算机导论课程中,成为其中一个章节。
比如 Berkeley 开设的导论课 CS 61A 就是以 Python 作为练习语言,但是似乎国内很少有高校开这种导论课。
但是 C、C++ 这种语言,不学个一两个月,连个像样的程序都写出来,这种才是适合开一门课。
先说一下学习 C 语言的目的,上面我说语言不是重点,这也包括 C 语言。
但是 C 语言特殊就特殊在它可能是唯一最适合用来学习一系列计算机基础课的工具和媒介。
比如操作系统,实验几乎都是用的纯 C 写的 lab;
又比如汇编,学习的时候可以和 C 语言对应起来,了解if、for、while、数组访问等对应汇编是怎么样的;
又比如学习计网,这里面有很多的网络协议,会有不同的 header 定义,这些 header 中很多都是按 bit 来划分字段的,用 C 语言的 union 和 struct 是最好操作这些字段的,Java 和 Python 等语言虽然也能表示,但是可控性会差很多,以前尝试过用 Python 去组装 IP 包头,非常的麻烦也不优雅。
并且 C 语言本身抽象层次非常低,语法也很简单,没什么语法糖,很贴近操作系统。
而其它很多解释型语言会存在虚拟机这一层,虚拟机对我们算是一个黑盒,不利于透过语言去理解计算机的一些行为。
所以我之前在《如何成为一个计算机知识体系完整的毕业生》中把 C 语言也列为计算机专业的基础,而且是程序员必学的知识。
C 语言已经走过了四十多年的历史,但是在今天,任然常年霸占 TIOBE 编程语言排行榜前三,甚至榜首,这足以说明它是一门经久不衰的语言。
在日新月异的计算机行业,一个历经四十多年任然流行的技术,才是需要我们去关注和学习的经典。
我在那篇文章中说 C 语言是最适合用来理解计算机系统底层机制的语言,那今天就详细说说,这些底层机制都有哪些:
内存
一名合格的程序员必须了解内存,学习 C 语言是了解内存布局最直接、有效的途径,大家可以看到之前讲解指针那篇文章--深入理解内存和指针,全部都是从内存、内存布局出发进行讲解。
堆栈
理解不同的内存分配和管理方式,一种编译器自动管理,一种是手动管理。
函数调用栈、返回值
理解函数调用的本质,即跳转指令,理解返回值是怎么返回的。
系统调用
比如理解文件描述符,知道文件、socket 这些都被抽象成了fd。
指针
指针也是其它语言中引用的基础,深入理解指针对于理解引用也有很大帮助。
就拿文件来说,在 C 语言 中经常会接触到 read、write 系统函数,清楚操作的打开文件对应的是文件描述符。
而文件描述符是有限的,所以你知道用完 fd 后要及时关闭。
甚至用到 socket 网络编程的时候会发现,socket 返回的也是 fd,居然网络数据也能通过 read、write 去读写。
深刻的体会到 Unix 哲学:一切皆文件。
而在 Java、Python、PHP 这些语言中,打开一个文件只需要调用 File.open 或是 open,然后就可以拿到一个对象,然后对这个对象去调用读写方法进行操作。
但这时候文件对于我们更像是一个资源,全部的细节都被对象屏蔽了,而老师说资源是有限的,所以用完了要及时释放。
而你也不知道如果不释放这些资源会有什么后果,只是听老师说用完的资源及时释放是个好习惯。
在这里,操作系统的文件系统、进程等很多实现机制就被 JVM、Python 虚拟机所隐藏了。
而和操作系统等密切相关的底层机制也只有通过学习 C 语言才能透彻地理解它们。
这里又有个矛盾,上面说的这些内容其实不单单是 C 语言课所教的,其中还包括《组成原理》、《汇编》、《操作系统》等。
所以就出现了很多同学说的,就算上了 C 语言课,上面这些很多原理也还是不知道呀。
当然,这些内容是需要在大二、大三上专业课逐渐补齐的,但是先学 C 语言给学习这些内容打下了一个基础,大一把内存和指针理解透彻就好了,这就是前置条件。
而如果大一不上 C 语言,那么后续需要用到 C 语言的时候,自学的难度会高于自学 Python、Java 等语言。
比如有些学校在操作系统课会引入一些国外的 Lab,诸如 MIT 6.828 xv6 那样的 mini os,需要学生动手去完成一些内存管理、多线程实现、文件系统等操作系统核心模块。
比如清华 OS 课程用的 ucore,哈工大 OS 课程用的 linux-0.11,这些都是纯 C 写的。
如果没 C 的基础,连实验都没法继续,而这些实验算是操作系统课程的精髓了。
所以这才是我认为大一先上 C 语言的核心原因:
一是语法简单,更加贴近计算机本质的一些东西,学 C 也不是简单的学语言本身,而是想透过 C 语言去理解一些如寄存器、内存、函数调用、跳转等东西。
二是为大二、大三阶段的专业课打下一个基础,当然很多同学说我不学 C 一样可以学操作系统、计网呀。
当然,这些和 C 没必然关联,只是很多实验你确实不好继续做,除非你只打算看看概念,背背什么是进程、线程。
我认为 C 语言最为核心的有三块:
指针
内存
系统编程
首先指针和内存是需要在学习 C 语言过程中就理解、搞定的,推荐两本书:
《C程序设计语言》、《C和指针》
如果你觉得初学看书过于困难,那么可以去中国大学 MOOC 上浙大翁凯老师的 C 语言课,可以直接去 B 站搜。
视频结合书一起看,相信会理解得更加深刻。
然后,学习完了 C 语言基本语法后,你会发现似乎只能开发在黑窗口里运行的程序,写不出那些漂亮的 GUI。
确实,C 语言本来就不擅长做这些,C 语言擅长的是开发系统组件来支撑上层应用。
但是如果你迫切的想做出一些可视化、有趣的东西,那么可以这样做:
找一些 C 语言的图形库,比如 easyx,借助这些图形库,你完全可以实现一些图形界面的游戏。
继续去学 Python、Java 这种语言,然后学习 Web 开发,写写网页。
当然了,如果你对那些可视化的东西没那么大兴趣,甚至还挺喜欢黑窗口的,那么恭喜你,你有成为大佬的潜质。
当你熟悉完 C 语言基本的语法以后,建议去学习数据结构与算法,用 C 语言去实现链表、树、二叉树、堆、排序、搜索等等。
推荐看看《算法:C语言实现》这本书。
如果能通过 void 指针实现一些泛型数据结构就更棒了,比如标准库里的 qsort 就能支持任意可比较结构体排序。
然后,时间应该很快来到了大二、大三,这时候你应该学习系统编程,什么是系统编程呢,其实就是 CSAPP 这本书上所讲授的内容。
系统编程其实就是学习如何用 C 语言编写出真正可用的软件,比如像 http server、redis 这种,会涉及到:
如何在 Linux 环境下编程
系统级接口(system-level interface)究竟是什么
Linux 内核和 C 标准库提供了哪些能力
Linux 的系统调用是怎样实现的
都有哪些系统调用,如何使用
其它诸如mutex、signal、select、epoll、ipc、socket、thread、process(fork)等等
当然,还有一些同学会选择继续学习 Java 这种,比如 JVM、多线程、Java Web 等等,这也是没问题的。
但是,相信我,就算你以后不会用到 C 去编程,利用大学大把的时间去深入学习一些底层的知识。
也是对深入学习 Java 有好处的,比如你学 Netty、 Java 的 NIO 最终都要回到 Linux 系统的 epoll、select 上。
系统编程推荐《深入理解计算机系统》、《Unix网络编程》、《Unix高级环境编程》,Windows 下的我基本没学过,所以就不推荐了。
这就是 Java、Python 之下的世界,相信 Javaer 都学习过 JVM 的原理,了解过 GC、类加载机制、运行时数据区等知识。
但实际上,JVM 也只是介于操作系统之间的一个中间层。
很多时候 JVM、Python 解释器等本身都是需要 Native 本地方法栈去和 OS 打交道的,去和系统调用接口交互。
所以 Linux 系统编程对于深入学习编程一定是绕不开(因为很多服务端程序都是运行在Linux上的,所以忽略了Win/Mac
而这是 C 语言的世界:
所以 C 的重要性不需要的多说了吧~
不少 Java、C#、PHP、Python 程序员工作几年后会遇到瓶颈,有些会回来学习 C 语言,重拾底层概念,寻求新的突破。
这里不是在否定其它非 C 程序员就没技术,实际上我本身也不写 C,我只是想表达如果你想学习底层机制、操作系统等,请学习 C 语言。
编程学到一定的时候,你就需要了解底层系统的机制,否则,知其然不知所以然。
真正的高手往往都是有很强的系统性基础知识的,表面的东西永远是肤浅的。
所以利用大学的时间恰恰是打好这些基础的关键时间,等到工作了,大家都是更倾向于学习快速上手业务的技能。
所以,在大学里先学什么语言不重要,你可以先学 Python、Java,但是无论如何,如果你想学好 Computer Science,C 语言一定绕不开。
也许以后实际工作中你完全没有机会去写 C,但是这并没关系,打好了基础,学其它也会学得很快、很透彻。
对于计算机专业的同学,还是建议学好 C 语言,与其它课程相结合,多懂一点程序背后的实现原理。
最后上两张图,什么叫真正的技术啊(战术后仰
还教微服务,这种不是玩概念么?
不去公司上手真正的微服务项目,在学校、培训班搭微服务?
这种东西学习下概念和思想就好了,这些东西根本就是应用层的东西,学习起来根本不费劲的好吧。
我敢保证,没有一个 985 会教微服务这种东西,分布式理论倒是可能会单独开一门课。
不过我相信上面图片里的这个分布式一定不会教CAP、Raft、Paxos 这些东西,大概率是用 Springboot + Dubbo + Zookeeper 在几台机器搭建一个服务。。。
而这是科班的学习路线,先不说这些课程有多少是学过就忘了的,但至少你需要用到的时候知道去哪捡起来,怎么捡。
不过讲道理两张图片,殊途同归,最后都是码农,只不过大概率决定了你在哪里敲代码。
总结一下,BB 了这么多,就想表达一个意思,C 语言很重要,如果你正在大学学 C,一定要掌握好,不要怀疑学 C 有没有用。