嵌入式C语言自我修养:从芯片、编译器到操作系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

前言

C语言是很多人学习编程的第一门语言。很多初学者在学习过程中,往往会产生各种各样的疑惑:C语言黑屏白字,窗口界面看起来甚至还有点丑陋,现在学这个还有用吗?能编写一个好玩的App吗?能写爬虫吗?能搭建一个电商网站吗?光靠C语言能找到一份月薪过万的工作吗?现在互联网和人工智能这么火,大家都在学习Java、Python、Ruby……都2021年了,C语言是不是已经过时了?

C语言已经过时了吗

C语言并没有过时。自C语言问世几十年来,其实一直都是使用最广泛的编程语言之一,多年来一直低调地霸占着编程语言的“琅琊榜”,目前还没有看到衰退和被替代的迹象。只不过在Android、移动互联网火了之后,Java暂时抢了风头而已,把C语言从编程语言排行榜上挤到了第二的位置。沧海桑田,时过境迁,很多编程语言如过江之鲫,风云变幻,但C语言依然宝刀未老,在编程语言排行榜上从未跌出过前三,这也从侧面说明了C语言一直都是被广泛使用的编程语言。既然C语言被广泛使用,那么主要应用在哪些领域呢?可以这么说,基本上在每个领域都可以看到C语言的身影。

● 应用软件:Linux/UNIX环境下的工具、应用程序。

● 系统软件:操作系统、编译器、数据库、图形处理、虚拟机、多媒体库等。

● 嵌入式开发:各种RTOS、BSP、固件、驱动、API库。

● 嵌入式、工业控制、物联网、消费电子、科研领域、数值计算。

● 实现其他编程/脚本语言:Lua、Python、Shell。

● 网站服务器底层、游戏、各种应用框架。

C语言是一门高级语言。C语言有高级语言的各种语法和特性,我们使用C语言可以构建大型的软件工程。有人说,C语言小打小闹,上不了大台面,编写不了大型的项目,这个说法其实也是站不住脚的:很多大型的GNU开源项目,其实都是使用C语言开发的,如Lua脚本语言、SQLite、Nginx、UNIX等。现在市面上几乎所有的操作系统都是使用C语言开发的,如Linux内核、uC/OS、VxWorks、FreeRTOS。目前最新的Linux-5.x内核代码已多达2000万行,3万多个源文件,这个项目应该不算小了吧!

C语言也是一门低级语言。通过指针和位运算,我们可以修改内存和寄存器,从而直接控制CPU和硬件电路的运行。正是由于这种低级特性,很多操作系统内核、驱动都选择使用C语言进行开发。尤其在嵌入式开发领域,C语言被广泛使用,C语言是嵌入式工程师必须熟练掌握,甚至需要精通的一门编程语言。

C语言到底要学到什么程度

学习C语言到底要学到什么程度,才能达到面试的要求,才能胜任一份嵌入式开发的工作呢?这是很多嵌入式初学者很关心的问题。

一般来讲,不同的行业领域、不同的C语言开发岗位、不同的学习目的,对C语言的要求也不一样。如图0-1所示,如果你是在校学生,学习C语言仅仅是为了应付期末考试、过计算机二级考试、考证,那么你只要把C语言的基本语法掌握好,基本上就可以轻松过关,稍微用心点,说不定还能拿个优秀。如果你想做C语言桌面软件、网站服务器开发,那么你不仅要学习C语言的基本语法,还要对特定行业领域的专业知识、软件工程、项目管理等有所涉猎。这可不像过计算机二级考试那么简单。计算机二级考试其实压根就不是为程序员准备的,它是非计算机专业学生的终极目标,而对于一个立志从事软件开发的工程师来说,它仅仅是一个起点。如果你想以后从事嵌入式开发、Linux内核驱动开发等工作,那么对C语言的要求就更高了:你不仅要掌握C语言的基本语法、项目管理、软件工程,还要对硬件电路、CPU、操作系统、编译原理等底层机制有完整的了解,需要对C语言进行进一步的强化学习和编程训练。

图0-1 C语言各种开发岗位和学习需求

使用C语言编程就像写小说一样:为什么你掌握了3000个常用的英文单词、八大时态、各种从句语法,还是写不出《哈姆雷特》《冰与火之歌》呢?道理其实很简单,单词和语法只是基础中的基础,只是工具而已。要想写出优秀的小说,还需要对一门语言背后的社会背景、历史文化、思维逻辑、风土人情等有深入的理解和把握才行。

测一测你的C语言水平

为了达到更好的学习效果,下面特意列出了一些问题,用来测评你真实的C语言水平。

C语言测试(1):基本概念考查

● 什么是标识符、关键字和预定义标识符?三者有何区别?

● 在C程序编译过程中,什么是语法检查、语义检查?两者有何区别?

● 什么是表达式?什么是语句?什么是代码块?

● 什么是左值、右值、对象、副作用、未定义行为?

● 什么是结合性、左结合、右结合?

C语言测试(2):一个sizeof(int)引发的思考

● sizeof是函数,是关键字,还是预定义标识符?

● 在32位和64位的Windows 7环境下运行,结果分别是多少?

● 在32位和64位的X86 CPU平台下运行,结果分别是多少?

● 在8位、16位、32位的单片机环境下运行,结果分别是多少?

● 在32位ARM和64位ARM下运行,结果分别是多少?

● 分别在VC++6.0、Turbo C、Keil、32位/64位GCC编译器下编译、运行,结果一样吗?

● 使用32位GCC编译器编译生成32位可执行文件,运行在64位环境下,结果如何?

● 使用64位GCC编译器编译生成64位可执行文件,运行在32位环境下,结果如何?

C语言测试(3):自增运算符

使用不同的编译器编译、运行下面的程序代码,结果分别是多少?结果是否一定相同?为什么?

C语言测试(4):程序代码分析

阅读上面的程序代码,然后进行如下操作,观察运行结果并分析。

● 分别使用C-Free、GCC、VC++6.0、Visual Studio编译、运行代码,运行结果一定相同吗?会出现什么问题?为什么?

● 在VC++6.0环境下,新建console工程,将上面的程序代码分别保存为.cpp和.c文件并编译、运行,运行结果会如何?为什么?

C语言测试(5):程序运行内存分析

在32位Linux下,编写一个数据复制函数,在实际运行中会出现什么问题?

C语言测试(6):程序改错题

在嵌入式ARM裸机平台上,实现一个MP3播放器,要求实现如下功能:当不同的控制按键被按下时,播放器可以播放、暂停、播放上一首歌曲、播放下一首歌曲。为了实现这些功能,我们设计了一个按键中断处理函数:当有按键被按下时,会产生一个中断,我们在按键中断处理函数中读取按键的值,并根据按键的值执行不同的操作。下面设计的按键中断处理函数中有很多不合理之处,请找出6处以上。

C语言测试(7):Linux内核代码分析

在Linux内核源码中存在着各种各样、稀奇古怪的C语言语法,试分析下面代码中宏定义、零长度数组、位运算、结构体变量初始化的作用。

C语言测试(8):Linux内核代码赏析

在Linux内核源码中,我们经常可以看到下面的代码风格,试分析它们的意义。

你要学习的,不仅仅是C语言……

对于上面的几个C语言测试,如果你已经知道了答案,并且知道其要考查的是什么知识点,恭喜你,你对C语言及计算机体系结构的知识已经很熟悉了。如果回答得不是很好,偷偷用百度也没有搜到理想的答案,也不用气馁,因为这次测试要考查的内容其实已经不仅仅是C语言的知识了,而是和嵌入式C语言开发相关的一些理论知识,如处理器架构、操作系统、编译原理、编译器特性、内存堆栈管理、Linux内核中的GNU C扩展语法等。

当然,上面的测试也不是为了故意扎你心或者卖关子,让你赶紧掏腰包买下这本书,而是想要传递一个信息:要想从事嵌入式开发工作,尤其是嵌入式Linux内核驱动开发工作,你要精通的不仅仅是C语言,最好还要掌握和C语言相关的一系列基础理论和调试技能。笔者也是过来人,从最初学习嵌入式到从事嵌入式开发工作,这一路走来坎坷崎岖,什么都不说了,说多了都是泪。从一开始连指针都不会用、不敢用,看内核驱动代码一头雾水,越看越没底、越看越没自信,到现在不再犯怵,有自信和能力看懂内核中的代码细节和系统框架,这种进步不是天上掉下来的,也不是一不小心跌入山洞,捡到武功秘籍练出来的,而是不断地学习和实践、反复迭代、不断完善自己的知识体系和技能树,才慢慢达到的。学习没有捷径可走,要想真正学好嵌入式、精通嵌入式,个人觉得除了精通C语言,最好还要具备以下完整的知识体系和编程技能。

● 半导体基础、CPU工作原理、硬件电路、计算机系统结构。

● ARM体系结构与汇编指令、汇编程序设计、ARM反汇编分析。

● 程序的编译、链接、安装、运行和重定位分析。

● 熟悉C语言标准、ARM、GNU编译器的特性和扩展语法。

● C语言的模块化编程思想,学会使用模块化思想去分析复杂的系统。

● C语言的面向对象编程(简称OOP)思想,学会使用OOP思想去分析Linux内核驱动。

● 对指针的深刻理解,对复杂指针的声明和灵活应用。

● 对内存堆栈管理、内存泄漏、栈溢出、段错误的深刻理解。

● 多任务并发编程思想,CPU和操作系统基础理论。

本书内容及写作初衷

本书从C语言的角度出发,分10章,在默认读者已经掌握C语言基本语法的基础上,和大家一起探讨、学习C语言背后的CPU工作原理、计算机体系结构、ARM平台下程序的编译/链接、程序运行时的内存堆栈管理等底层知识。同时,针对嵌入式开发领域,用3章分别探讨了C语言的面向对象编程思想、模块化编程思想和多任务编程思想,这些底层知识和编程思想构成了嵌入式开发所需要的通用理论基础和核心技能。尤其是对于很多从不同专业转行到嵌入式开发的朋友,由于专业背景的差异,导致每个人的知识储备和编程技能树参差不齐,在学习嵌入式开发的过程中会经常遇到各种各样的问题,陷入学习的困境。

本书的写作初衷就是为不同专业背景的读者搭建嵌入式开发所需要的完整知识体系和认知框架。掌握了这些基础理论和编程技能,也就补齐了短板,可为后续的嵌入式开发进阶学习打下坚实的基础。

本书特色

● 大白话写作风格,通俗易懂,不怕学不会,就怕你不学。

● 大量的配图、原理图,图文并茂,更加有利于学习和理解。

● 在ARM平台下讲解程序的编译、链接和运行原理(独创)。

● 现场“手撕”ARM汇编代码,从反汇编角度剖析C函数调用、传参过程。

● 多角度剖析C语言:CPU、计算机体系结构、编译器、操作系统、软件工程。

● GNU C编译器扩展语法精讲(在GNU开源软件、Linux内核中大量使用)。

● 内存堆栈管理机制的底层剖析,从根源上理解内存错误。

● 从零开始一步一步搭建和迭代嵌入式软件框架。

● 教你用OOP思想分析Linux内核中复杂的驱动和子系统。

● C语言的多任务并发编程思想,CPU和操作系统零基础入门。

读者定位

本书针对的是嵌入式开发,尤其是嵌入式Linux开发背景下的C语言进阶学习,比较适合在校学生、嵌入式学员、工作1~3年的职场新兵阅读和学习。为了达到更好的学习效果,在阅读本书之前,首先要确保你已经掌握了C语言的基本语法,并且至少使用过一款C语言集成开发环境(VC++6.0、Visual Studio、C-Free、GCC都可以),开发过一个完整的C语言项目(课程设计也算)。有了这些基础和编程经验之后,学习效果会更好。

致谢及意见反馈

本书在写作过程中参考了很多经典图书、论文期刊、开源代码,包括互联网上的很多电子资料,由于时间和精力的关系,无法对这些资料的最初出处一一溯本求源,对各种资料的创建者和分享者不能一一列举。这里对他们的贡献表示真诚的感谢。

感谢电子工业出版社的董英和李秀梅编辑,本书从选题的论证到书稿的格式审核、文字编辑,她们都付出了辛苦的劳动并提出了很多专业意见。鉴于作者水平、时间和精力有限,书中难免出现一些错误。如果你在阅读过程中发现了错误或者需要改进的地方,欢迎和我联系(E-mail:3284757626@qq.com),或者在我的个人博客(www.zhaixue.cc)上留言,或者扫码关注微信公众号“宅学部落”。