作者:empty 页数:94 出版社:empty |
本电子书籍是根据《C语嵌入式Linux高级编程》第05期:Linux GNU C语法扩属视频教程改编, 主要内容主要分为两部分·讲解Linux内核, 开源软件中常用的GNU C扩展语法·微信公众号宅学部落,2018年发布的关于C语言、嵌入式技术文章汇总木电子书籍会不断更新、完善,添加新的内容,想获取最新版木的电子书籍信息,可以注微信公众号:宅学部落(arm liu x fun) 嵌入式视频淘宝店:https//wang lita o.taobao.com第01课:Linux内核中的C语言语法扩展
1.1 Linux内核驱动中的奇怪语法大家在看一些GNU开源软件, 或者阅读Linux内核、驱动码时会发現, 在Linux内核源码中, 有大量的C程序看起来怪怪的, 说它是C语言吧,貌以又跟教材中的写法不太一样;说它不是C语声呢,但是这些程序确确实实是在一个C文件中,此时,你肯定怀疑你看到的是一个假的C语言”!比如,下面的宏定义你没有看错, 这些其实也是C语言, 但并不是标准的C语言语法, 而是我们Lnux内核使用的GNU C编译恕扩展的一些C语言语法, 这些语法在C语言教材或资料中一般不会提及, 所以你才会似曾相识而又感到生, 看起来感觉怪怪的, 我们在做Linux驱动开发, 或者阅读Linux内核源码过程中, 会经常测到这些奇古怪的甩法, 如果不去了解这些特殊语法的具体含义, 可能就对代码的理解造成一定本教程, 就是带领大家一起去了解Linux内核或者GNU开添软件中, 常用的一些C语言特殊语法扩展, 扫读Linux内核或GNU开在进入正式课程之前,先给大家普及一下C标准的概念,在学习C语言时,大家在教材或留料上,或多或少可能见到过 AN51C的字眼.
1.2C语言标准和编译器可能当时没有太在意, 其实ANSIC表示的就是C语言标准,什么是C语言标准呢?我们生活的现实世界,就是由各种标准构成的,正是这些标准,我们的社会才会有条不亲的运行,比如我们过马路,避循的交通规则就是一个标准:红灯停,绿灯行,黄灯亮了等一等,当行人和司机都遵循这个默认的标准时,我们的交通系统才会顺畅运行, 电脑中的USB接也是一种标准, 当大家生产的USB产品都遵循USB协议这种通信标准时, 我们的手机、U盘、USB摄像头、USB网卡才可以在各种电脑设备上互插互拔, 2G、3G.4G也是一种标准, 当不同厂家生产的基带芯片都通循这种通信标准, 我们所用的不同品牌、不同操作系统的手机才可能互相打电话,互相发微恼、互相给对方点赞。同样,C语言也有它自己的标准,我们知道,C语言程序需要通过编译器,编译生成二讲制指令,才册在我们的电脑上运行,在C语言刚发布的早期,各大编译器厂商开发自己的编译器时,各自开发,各自维护,时间久了,就会变得比较混乱。这就会造成这样一种局面:程序员写的程序,在一个编译器上编译通过,在另一个编译器编译通不过,大家按各白的习惯来,谁也不服准,就像春秋战国时代:不同的货币,不同的度量街,不同的文字,都是中国人,因为标准不统一,所以交流起来很麻烦,这样下去也不是办法,后来ANSI(AMERICAN NATIONAL 5 TANDARDS INSTITUTE:美国国家标准协会, 简称AN5I) 出山了, 联合150(国际化标准组织) 召集各个编译解厂商大佬,各种技术团体,一起喝个茶、开个碰头会,开始启动C语言的标准化工作,期问各种大佬之问也是矛盾重重,充满各种争议,但功夫不负有心人,经过难的碰商,终于在1989年达成一致,发布了C语言标准,后来第二年又做了一些改进,于是,就像秦始皇统一六国、统一文字和度量衡一样,C语言标准终于问世了!因为是在1989年发布的,所以人们一般称其为C89或C90标准, 或者叫微ANSIC.
K&RC一般也称为传统C, 在C标准没有统一之前, C语言的作者Dennis Ritchie和Brian Kernighan合作写了一本书《C程序设计语言),早期程序员编程,这本书可以说是绝对权威,这本书很薄,内容练,主要介绍了C语言的基本使用方法,后来《C程序设计语言) 第二版问世, 做了一些修改:比如新增unsigned int, longint, struct等数据类型; 把运算符“+/--修改为+/, 避免运算符带来的一些歧文和Bug.这本书可以看作是ANSI标准的形, 但期的C语言还是很简单的, 比如还没有定义标准库函数、没有预处理命令等,
ANSIC是ANSI(美国国家标准协会) 在K&RC的基础上, 统一了各人编译器厂商的不同标准, 井对C语言语法和特性做了一些矿展,而发布的一个标准, 这个标准一般也叫做C 89/C 90, 也是目前各种编译器默认支持的C语言标准, ANSIC主要新增了以下特性·增加signed、volatile、const关键学
除此之外,C99标准借签其它语言的一些优点,对语法和函故做了一系列改进,大大方便了程序员开发程序,比如:·变量声明可以放代码快的任何地方,AN51C规定变量的声明要全部写在函数语句的最前面,否则就会报猎误,现在不需要这样·源程序每行最大支持4095个字节,这个貌似足够用了,没有什么程序能复杂到一行程序有4KB个字符;·支持//单行注释, ANSIC使用/**/没有C*+的W注释方便, 所以C 99新标准借鉴过来了, 也开始支持这种注释方式;·标准库新增了一些头文件:如std bool.h、complex.h.stdarg.h、fen vh等, 大家在C语言中经常返回的true、false, 其实这也是写了,哪里需要使用变量,在哪里直接声明使用即可,C++里面定义的b aol类型, 那为什么我们经常这样写, 而编器编译程序时没有报呢, 这是因为早期大家编程使用的都是VC++6.0系列, 是C++编译器, 还有一种可能就是有些IDE对这个数据类型的数据做了封装,C11新标准C 11标准是2011年发布的最新C语言标准, 修改了C语言标准的一些Bug.新赠了一然特性:·增加_Na return, 声明函数无返回值;·增加_Generic:支持泛型编程;·修改了标准库函数的一些Bug:如gets() 函散被gets_50函敌代替;·新增文件锁功能;·支持多线程,从C11标准的修改内容来看,也慢慢察觉到C语言来来的发展趋势:C语言现在也在借整现在编程语言的优点,不断添却到自己的标准里面,比如现代编程语言的多线程、字符串,泛里编程等,C语言最新的标准都支持,但是这样下去,C语言是不是还能保持她简单就是美的优雅特色呢,我们只能慢慢期待了,但至少目前我们不用担心这些,因为C11新发布的标准,目前绝大多数编译器还不支持,所以我们暂时还用不到.1.5编译器对C标准的支持标准是一回事,各种编译图支不支持是另一回事,这一点,大家要接清楚,这就手机一样,不同时期发布的手机对通信标准支持也不一样,早期的手机可能只支持2G通信,后来支持3G,现在发布的新款手机基本上都支持4G了,而月可以兼容2G/3G,现在5G标准正在研发,快发布了,挺说2019年发布,2020年商用,但是目前还没有手机支持5G通信,就跟现在没有编译支持C11标准一样,不同编译器, 甚至对C标准的支持也不一样, 有的编译器只支持ANSIC, 这是目前默认的C标准, 有的纳译器可以支持C 99, 或者支持C 99标准的部分特性, 目前对C 99标准支持最好的是GNU C编译器, 据说可以支持C 99标准99W的新增特性.1.6编译器对C标准的扩展不同编译器,出于开发环境、硬性平台,性能优化的需要,除了支持C标准外,还会自己做一些扩展,在51单片机上用C语开发程序, 我们经常使用Keil for C 51集成开发环境。你会发现Keil for CS 1或其他IDE王的C编译器会对C语言标准作很多扩展,比如增加各种关字·data:RAM的低128B空间,单周期直接寻址:·code表示程序存储区:·bit位变量, 常用来定文单片机的PD-P 3管脚:·s bit:特殊功能位变量,·sfr特殊功能寄存器:·reentrant:重入函数声明
如果您手头暂时没有Linux学习环境, 也可以在Windows环境下安装C-Free学习, 教程中的C语言示例程序在C-Free环境下面也能编译通过, 当然在这里, 还是建议您使用虚拟机安装一个Linux学习环境, 一个良好的环境更有利于我们的学习, 在安装过程有什么疑感,可以通过邮件(3284757626@9959m)与我联系,也可以加入QQ群(475504428),参与技术讨论,第02课:Linux内核驱动中的指定初始化2.1什么是指定初始化在标准C中,当我们定义并初始化一个数组时,常用方法如下:int a[10] ={0, 1.2.3, 4.5, 5.7.4按服这种固定的顺序,我们可以依次给a[0]和a[8]值。因为没有对a(9]值,所以译器会将9默认设置为0.当故组长度比较小时,使用这种方式初始化比较方便,当数组比较大,而且数组里的非零元素并不连续时,这时候再按照固定顺序初始化就比较麻烦了,比如,我们定义一个数组b[100],其中b[10].b/30]需爱初始化,如果还接照前面的固定顺序初始化,0中的初始化数据中间可能要填充大量的0,比较麻场,那怎么办呢?C99标准改进了数组的初始化方式,支持指定任意元素初始化,不再按照定的顺序初始化,1ntb[100] ={[10] -1.[30] =2} ;通过数组素引,我们可以直给指定的数组元素佰,徐此之外,一个结构体变量的韧始化,也可以通过指定某个结构体域直接赋值,因为GNU C支持C 99标准, 所以GCC编译也支持这一特性, 甚至早期不支持C 99, 只支持C 89的GCC编译路版本, 这一特性也被当作一个GCC编译器的扩展特性来提供给程序员使用,2.2指定初始化数组元素在GNU C中, 通过数组元素索引, 我们就可以给某个指定的元素直接照值,in tb[100] ={[10] =1, [30] =2] ;在(}中,我们通过[10]数组元素素引,就可以直接给副[10]怕了,这里有个细节注意一下,就是各个值之问用逗号隔开,而不是使用分号 1 ,如果我们想给数组中某一个索引范围的数组元素初始化,可以采用下面的方式,
在程序中, 我们定义一个结构体类型student, 然后分别定义两个结构体变量stu 1和stu 2, 初始化stu 1时, 我们采用标准C的始化方式, 即接固定膜序直接初始化, 初始化stu 2时, 我们采用GNU C的韧始化方式, 遇过结构域名.name和.age, 我们就可以给结构体变量的某一个指定成员直接值,非常方便,2.4 Linux内核驱动注册在Linux内核驱动中, 大量使用GNU C的这种指定初始化方式, 通过结构体成员来初始化结构体变量, 比如在字符驱动程序中, 我们经常见到这样的韧始化static const struct file_operations ab 3100_otp_operations={在范动程序中, 我们经常使用file_operations这个结构体变最来注朋我们开发的拒动, 然后以回调的方式来执行我们驱动实现的相关功能, 结构体f1e_operations在Lnux内核中的定义如下:结构体file_operations里面定义了很多结构体成员, 而在这个驱动中, 我们只初始化了部分成员变量, 通过访问结构体的成员来这种指定初始化方式, 不仅使用灵活, 而且还有一个好处就是:代码易于维护, 尤其是在Linux内核这种大型项目中, 几万个文件, 几千万的代码量, 当成百上干个文件都使用file_operations这个结构体类型来定义变量井初始化时, 那么一个很大的问题就来了:如果采用标准C那种技照固定顺序赋值, 当我们的file_operations结构体类型发生改变时, 如添加成员、减少成员, 调整成员顺序, 那么使用该结构体类型定义变量的大量C文件都需重新调整初始化序,牵一发而动全身,想想这是多么可怕!我们通过指定初始化方式, 就可以避免这个问题, 无论fila_opa rations结构体类型如何变化, 添加成员也好、减少成员也好、调整成员顺序也好,都不会影书其它文件的使用,有了指定初始化,再也不用加班修改代码了,妈妈再也不用担心我们整日加班,不回家吃饭表达式和语句是C语言中的基础规念,什么是表达式呢?表达式就是由一系列操作符和操作数构成的式子,操作符可以是C语言标准规定的各种算术运算符、逻运算符、赋值运算符、比较运算符等,操作数可以是一个常量,也可以是一个变量,表达式也可以没有操作符,表达式一般用来据计算或实现某种功能的算法,表达式有2个基本属性:慎和类型,如上面的表达式2+3,它的值为5,根据操作符的不