1.1Linux内核驱动中的奇怪句型
你们在看一些GNU开源软件,或则阅读Linux内核、驱动源码时会发觉,在Linux内核源码中,有大量的C程序看上去“怪怪的”。说它是C语言吧,似乎又跟教材中的写法不太一样;说它不是C语言呢,然而这种程序确确实实是在一个C文件中。此时,你肯定怀疑你听到的是一个“假的C语言”!
例如,下边的宏定义:
字符驱动的填充:
内核中实现复印功能的宏定义:
你没有看错,这种虽然也是C语言,但并不是标准的C语言句型,而是我们Linux内核使用的GNUC编译器扩充的一些C语言句型。这种句型在C语言教材或资料中通常不会提到,所以你就会似曾相恋而又倍感陌生,看上去觉得“怪怪的”。我们在做Linux驱动开发,或则阅读Linux内核源码过程中,会时常遇见那些“稀奇奇特”的用法,倘若不去了解这种特殊句型的具体含意,可能就对代码的理解导致一定障碍。
本教程,就是率领你们一起去了解Linux内核或则GNU开源软件中,常用的一些C语言特殊句型扩充,扫除阅读Linux内核或GNU开源软件时,这种扩充特点带给我们的句型阅读障碍和疑惑。
1.2C语言标准和编译器
在步入即将课程之前,先给你们普及一下C标准的概念。在学习C语言时,你们在教材或资料上,或多或少可能看见过“ANSIC”的字眼。可能当时没有太在乎,虽然“ANSIC”表示的就是C语言标准。
哪些是C语言标准呢?我们生活的现实世界,就是由各类标准构成的,正是这种标准,我们的社会就会有条不紊的运行。例如我们过马路,遵守的交通规则就是一个标准:红灯停,绿灯行,黄灯亮了等一等。当行人和司机都遵守这个默认的标准时,我们的交通系统才能顺畅运行。笔记本中的USB插口也是一种标准,当你们生产的USB产品都遵守USB合同这些通讯标准时,我们的手机、U盘、USB摄像头、USB网卡才可以在各类笔记本设备上互插互拔。2G、3G、4G也是一种标准,当不同厂家生产的基带芯片都遵守这些通讯标准,我们所用的不同品牌、不同操作系统的手机才可能相互打电话、互相发陌陌、互相给对方点赞。
同样,C语言也有它自己的标准。我们晓得,C语言程序须要通过编译器,编译生成二补码指令,能够在我们的笔记本上运行。在C语言刚发布的初期,各大编译器厂商开发自己的编译器时,各自开发,各自维护,时间久了,才会显得比较混乱。这都会导致这样一种局面:程序员写的程序,在一个编译器上编译通过,在另一个编译器编译通不过。你们按各自的习惯来,谁也不服谁,如同春秋战国时代:不同的货币、不同的测度衡,不同的文字,都是中国人,由于标准不统一,所以交流上去很麻烦,这样下去也不是办法啊。
后来ANSI(AMERICANNATIONALSTANDARDSINSTITUTE:澳大利亚国家标准商会,简称ANSI)出山了,联合ISO(国际化标准组织)召集各个编译器厂商大鳄,各类技术团体,一起喝个茶、开个碰头会,开始启动C语言的标准化工作。期间各类大鳄之间也是矛盾重重,饱含各类争议,但工夫不负有心人,经过艰辛的谈判,总算在1989年达成一致,发布了C语言标准,后来第二年又做了一些改进。于是,如同秦始皇统一五国、统一文字和测度衡一样,C语言标准总算问世了!由于是在1989年发布的,所以人们通常称其为C89或C90标准,或则称作ANSIC。
1.3C标准内容
C标准里主要讲了哪些?
C标准英语文档,洋洋洒洒几百页,讲了好多东西,但总体归纳上去,主要就是C语言编程的一些句型惯例,例如:
C标准发布后,大伙都遵循这个标准:程序员开发程序时,根据这些标准写;编译器厂商开发编译器时,也根据这些标准去解析、翻译程序。不同的编译器厂商支持统一的标准,这样你们写的程序,使用不同的编译器,都可以正确编译、运行,大大提升程序的开发效率,促进了IT行业的发展。
1.4C标准的发展过程
C标准并不是永远不变的,就跟联通通讯一样,也是从2G、3G、4G到5G不断发展变化的。C标准也经历了下边四个阶段:
K&RC
K&RC通常俗称为传统C。在C标准没有统一之前,C语言的作者DennisRitchie和BrianKernighan合作写了一本书《C程序设计语言》。初期程序员编程,这本书可以说是绝对权威。这本书很薄,内容精炼,主要介绍了C语言的基本使用技巧。后来《C程序设计语言》第二版问世,做了一些更改:例如新增unsignedint、longint、struct等数据类型;把运算符=+/=-更改为+=/-=,防止运算符带来的一些歧义和Bug。这本书可以看作是ANSI标准的雏型。但初期的C语言还是很简单的,例如还没有定义标准库函数、没有预处理命令等。
ANSIC
ANSIC是ANSI(德国国家标准商会)在K&RC的基础上,统一了各大编译器厂商的不同标准,并对C语言句型和特点做了一些扩充,而发布的一个标准。这个标准通常也称作C89/C90,也是目前各类编译器默认支持的C语言标准。ANSIC主要新增了以下特点:
C99标准
C99标准是ANSI1999年在C89标准的基础上新发布的一个标准,该标准对ANSIC标准做了一些扩展,例如新增一些关键字,支持新的数据类型:
除此之外,C99标准也借鉴其它语言的一些优点,对句型和函数做了一系列改进,大大便捷了程序员开发程序,例如:
C11新标准
C11标准是2011年发布的最新C语言标准,更改了C语言标准的一些Bug、新增了一些特点:
从C11标准的更改内容来看,也渐渐察觉到C语言未来的发展趋势:C语言如今也在借鉴现今编程语言的优点,不断添加到自己的标准上面。诸如现代编程语言的多线程、字符串、泛型编程等,C语言最新的标准都支持。并且这样下去,C语言是不是能够保持她“简单就是美”的端庄特色呢,我们只能渐渐期盼了。但起码目前我们不用害怕这种,由于C11新发布的标准,目前绝大多数编译器还不支持,所以我们暂时还用不到。
1.5编译器对C标准的支持
标准是一回事c语言在线编译器手机,各类编译器支不支持是另一回事,这一点,你们要认清楚。这就跟手机一样,不同时期发布的手机对通讯标准支持也不一样。初期的手机可能只支持2G通讯,后来支持3G,现今发布的新品手机基本上都支持4G了,并且可以兼容2G/3G。
如今5G标准正在研制,快发布了,听说2019年发布,2020年商用。并且目前还没有手机支持5G通讯,就跟现今没有编译器支持C11标准一样。
不同编译器c语言在线编译器手机,甚至对C标准的支持也不一样。有的编译器只支持ANSIC,这是目前默认的C标准。有的编译器可以支持C99,或则支持C99标准的部份特点。目前对C99标准支持最好的是GNUC编译器,听说可以支持C99标准99%的新增特点。
1.6编译器对C标准的扩充
不同编译器,出于开发环境、硬件平台、性能优化的须要,不仅支持C标准外,都会自己做一些扩充。
在51单片机上用C语言开发程序,我们常常使用KeilforC51集成开发环境。你会发觉KeilforC51或其他IDE里的C编译器会对C语言标准作好多扩充。例如降低各类关键字:
假如你在程序中使用以上这种关键字,这么你的程序就只能使用51编译器来编译运行,你使用其它的编译器,例如VC++6.0,是编译通不过的。
同样的道理,GCC编译器,也对C标准做了好多扩充:
例如支持零厚度链表。这种新增的特点,C标准目前是不支持的,其它编译器也不支持。假如你在程序中定义一个零厚度字段:
int a[0];
只能使用GCC编译器能够正确编译,使用VC++6.0编译器编译可能就通不过,由于谷歌的C++编译器不支持这个特点。
1.7本教程主要内容
在GNU开源软件、Linux内核中会大量使用GCC自己扩充的句型,这会对我们理解开源软件、Linux内核代码带来一定障碍和困惑。本教程主要介绍GNUC对C标准扩充的一些常用句型和使用。终极目标是弄懂Linux内核驱动、GNU开源软件中这种特殊句型的应用,扫除这种特殊句型对我们理解内核代码带来的困惑和障碍。
1.8本教程须要的学习环境
在本教程讲解中,会使用一些arm-linux-gnueabi-gcc等命令拿来编译和反汇编程序。所以在学习本教程之前,确保你的笔记本上有如下Linux环境或源代码:
备注
假若您手头暂时没有Linux学习环境,也可以在Windows环境下安装C-Free学习。教程中的C语言示例程序在C-Free环境下边也能编译通过。其实在这儿,还是建议您使用虚拟机安装一个Linux学习环境,一个良好的环境更有利于我们的学习,在安装过程有哪些疑问,可以加入QQ群(475504428),参与技术讨论。