本文轉載自【微信公眾號:五角錢的程式設計師,ID:xianglin965】經微信公眾號授權轉載,如需轉載與原文作者聯繫
昨天晚上回家後突然在朋友圈發了個問卷,看下國內大學第一門語言到底有多少是用的 C 語言。
結果也是很符合預期,使用 C 語言做第一門程式語言課的大學達到了 90% 以上。
之前在知乎看見一個問題,問為什麼還有985高校給大一上 C 語言課,如下:
不過這個提問方式未免有引戰嫌疑,所以被知乎管理員編輯為如下問題:
這樣顯然中立很多了,是在擺事實提問題。
接下來我們就聊聊 985 大學為什麼還是給大一上 C 語言課。
一、為什麼要學 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 語言的優點
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程序設計語言》、《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
所以 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 有沒有用。
我是小北,咱們周末見~