一口气精通C语言

171 阅读11分钟

哈喽,我是子牙老师。今天我想通过一篇文章带你精通C语言,你信不信我能做到?好吧,问题不是我能不能做到,是你能不能学会。那咱们试试?

记得我在大学学习C语言的时候,一直有两个问题萦绕在心头:一、C语言有什么用?二、我应该如何构建实战环境,在实战中使用C语言。那时候甚至都不敢想精通,只想说我会用就行了,如今确实膨胀了,没办法,确实精通了。那我们就先从这两个朴素的问题切入

除上面提到的两个问题,本篇文章整体会讲到:

  1. 从全局角度看,当今科技世界,C语言的用途

  2. 精通C语言的标准是什么

  3. 如何构建实战环境,在实战中精通C语言

  4. 如何正确理解指针

  5. 带你非常容易就能玩透多级指针

  6. 打破认知,我把函数当整数去读写

  7. 再打破认知,我把整数当函数去执行

如果你能真正的消化掉我讲的这些,然后花时间做到,你就可以自信的说:我精通C语言啦!

以下,enjoy

C语言的用途

大学的C语言教材及老师的讲解,我只想说,讲得稀碎。学完我甚至都产生了怀疑:C语言没有传说中的那么牛叉呀!直到我自己玩透了C语言,并用C语言+汇编写了很多项目,做了很多课程,我才真正体会到,C语言的博大精深!

这是上个月发布的编程语言排行榜

你可能想说:C语言既然那么牛叉,为什么排到Python、C++、Java后面去了呢?因为开发应用,这三门语言确实效率高很多,但是你要知道的是,运行Python语言的Python虚拟机,就是用C语言写出来的。这就是C语言的一个重要用途:开发高级编程语言的虚拟机

我准备明年出一门课程《手写编程语言》,如果是你想学的,可以关注我公众号【硬核子牙】,等我消息

那Java语言呢?运行Java语言的虚拟机,即JVM,其实真正来说应该称为hotspot虚拟机,不是用C语言实现的,是用C++实现的。但是C++是在C语言的基础上发展来的,保留了C语言的绝大部分特性,基本完全兼容C语言,同时增加了更强大的面向对象机制、泛型、异常等

所以总结来说,C语言,几乎是所有高级编程语言的基石!C语言自1972年诞生于贝尔实验室至今,40多年,妥妥的江湖老大哥!可以这样说,C语言是程序员的分水岭,会跟不会,能力天差地别!未来的潜力也天差地别!

那既然Python、C++、Java开发效率更高,那都用这三门语言就好了,还要用C语言干吗?因为有的事情,Python、Java干不了,C++虽然能干,但是相对于C语言,会复杂很多,臃肿很多。比如开发操作系统、嵌入式开发

这就说到C语言的另一个重大用途:开发操作系统。 当今科技世界的地基,Linux内核,就是用汇编+C语言+硬编码实现的。


顺便提一嘴,我做了两个手写操作系统系列课程:《手写x86单核OS》《手写x64多核OS》,需要的可以V:jvm-anan

除了编程语言、操作系统,很多中间件也是用C语言实现的,比如大名鼎鼎的nginx、mysql、redis。这些都是我准备做的课程。我给自己的定位就是填补中国计算机底层市场的空白,做大家想学没地方学,别人不愿意做,或做不了的课程

你可能想说,这些都太庞大了,有没有小的应用我可以拿来练手的,有啊:内存池、线程池、协程、存储引擎、执行引擎、自实现面向对象机制……还有没有比这些更简单的?你这个问题,上帝都不知道怎么回答!

总结来说:

  1. C语言几乎是所有高级编程语言的地基,用于开发高级编程语言的编译器或运行时

  2. c++是在C语言的基础上发展而来的,保留了C语言的绝大部分特性,基本兼容C语言,同时增加了很多高级特性如面向对象、泛型、异常处理

  3. 很多强大的中间件如nginx、redis、mysql都是用C语言实现的,你不会c,你就研究不了这些,只能停留在表面,只能是一个普通的码农

  4. 开发操作系统,Linux内核驱动开发、嵌入式开发等特别底层的,一般都是汇编+C语言

  5. 对了,Linux提供的API,只有C语言版本,你不会C语言,你就玩不了Linux环境编程跟网络编程,你就无法实战Linux的进程线程机制、IPC、IO、网络,你就无法真正理解它们,在这之上的中间件,你就更加无法理解

关于C语言的用途,你get到了吗?了解到C语言能干这么多牛叉的事,你有没有冲动想把C语言玩明白,成为技术大牛,在计算机的世界中自由翱翔?成全你~

精通的标准

精通C语言的标准,就两个

如果你想学习我讲的汇编、C语言课程,关注公众号【硬核子牙】回复【C语言教程】,免费领取

一、你可以像编译器一样,看到C语言代码就知道会被编程成什么样, 这个需要汇编底子,不然看不懂。所以不会汇编的人,是不可能精通C语言的,只能说熟练掌握到什么程度

除了知道C语言代码会被如何编译,还要知道它的结构,比如一个函数由这些组成

二、你得知道C语言的所有数据类型的内存模样, 比如:基本数据类型、浮点型、数组、字符串、函数、结构体、联合体这些在内存中的样子,这点是你透彻理解指针,玩转指针的根基

在指针的眼里,没有数据类型一说,任何一块内存,都是可读可写可执行的,只是看有没有权限。其实权限不是C语言控制的,也不是编译器控制的,是CPU页机制控制的,是在加载程序时,根据编译器生成的信息,将权限考虑进去,做的内存映射(这段能理解说明功底还可以,不理解也没关系,需要操作系统、计算机组成原理那块的知识)

我举个例子吧,比如一个整数在内存中的样子,你得知道如何查看内存,不熟练的时候,要经常看内存

其实大端序、小端序,是很难记住的,但是你只要看内存,你不用死记硬背都知道。我不理解国内的教育,为什么都是死记硬背,连需要实战类的课程也是如此,又不去改变。大家都知道大学生毕业即失业,为什么没人去改变呢?想不通

通过看内存图,你还能总结出经验:大端小端,只影响占多个字节的基本类型、浮点型,数组、字符串、函数、结构体,在内存中都是顺序存储的

你脑海中有内存图,你才能与C语言合一,你才能没有约束,但是有规则的,灵活使用C语言,做你想做的任何事情,不会出错

还有一个内存图,就是堆栈图。 如果没有堆栈图,你是无法理解线程切换的,更别谈写操作系统,读懂Linux内核源码

如何构建环境去实战练习C语言,视频中有演示,自己看视频吧

正确理解指针

接下来说说C语言的核心:指针

记得大学教材上对指针的描述:指针就是内存的地址。这句话一下子就把学习指针的人带入了误区!指针,其实就是一种数据类型,只不过它比较特殊,它的特殊性刚好与内存地址相匹配,所以就把它两关联在了一起。所以学习指针,我们还是得先学明白它作为一种特殊数据类型的特性,才能透彻理解它,用好它

来一段测试代码

解释下这段代码想表达的意思:

  1. 基本数据类型,加1就是加1,符合我们学习的数学理论,所以c+1,i+1,虽然数据类型不同,结果都是2
  2. 指针类型的变量,加法的本质是加步长。什么意思呢?i_p+1=5是这样算出来的:i_p = sizeof(int) * 1 + 1。如果i_p+2,就要这么算sizeof(int) * 2 + 1 = 9

指针运算的时候,怎么知道步长是多少?将数据类型减去一个*,比如int的步长就是sizeof(int),int的步长就是sizeof(int)。指针变量不支持乘除运算、位运算、取模运算

指针作为一种特殊的数据类型,你悟了吗?大学里学起来那么吃力的指针,其实就是这么简单。只不过教你的人自己没玩明白,讲得特别复杂,讲解的方式又是错的,你学起来吃力还学不会

如果文字版理解起来吃力,可以看我讲的视频。关注公众号【硬核子牙】回复【C语言教程】,免费领取

玩转多级指针

你只有先理解了指针是一种特殊的数据类型,再将指针与内存地址关联起来,你自然而然就会了,接下来咱们把指针与内存关联起来理解

看图

解释一下:

  1. 普遍变量a,跟指针变量p,在内存中的样子是一样的,主流的也是小端序存储
  2. 指针变量,既可以将数值赋值给它,也可以取一个变量的地址赋值给它,编译后生成的指令是lea

这就是学习汇编的意义!

我之前做过一个小课《纯汇编写操作系统》,专门通过写操作系统帮助大家拿下汇编,感兴趣的可以V:jvm-anan

你理解了指针与内存之间的关系,并清晰的知道指针变量在内存中是如何存储的,那多级指针就很好理解了。多级指针的本质其实从语法上可以多次解引用。比如

变量ppp是两级指针,就可以取两次值

比如我想通过指针ppp拿到a的值,**ppp即可。指针变量ppp中存储的是指针变量pp的内存地址,所以ppp就相当于读0x18中的值,即0x20。第二个就是再次读0x20中的值,即10

p也是一个指针变量,它的值是常量10,如果我*p会发生什么呢?会去读内存地址10处的内存。一般这段内存,用户态是不可访问的,就会触发页异常。如果能访问呢?那你就稀里糊涂访问了未知的内存区域

如果文字版理解起来吃力,可以看我讲的视频。关注公众号【硬核子牙】回复【C语言教程】,免费领取

打破数据类型边界

有了上面的理解以后,我们就可以打破规则玩花样了

比如函数,在你的认知中,它只能运行,你从来没想过去读写它,那咱们来试试

定义一个函数test,用int*指针指向它,然后再去读函数的内存,结果是0x0005c5e9。结果怎么来的,右边的内存条已经告诉了你答案

顺便再从代码层面看下0x0005c5e9对应的指令是什么吧

透彻否?爽快否?这就是将汇编、C语言融会贯通后的实力!

通过阅读本文,你应该感受到我个人的C语言水平及我讲的C语言课程的水平。想精通C语言,学我的视频就够了,其他的视频都不用去看,浪费时间~