最初我是golang出生,当时做项目的时候java、c++、js、python都折腾过,但是关于c语言的接触,基本上都停留在大一的那个暑假。
后面一个项目需要写驱动,再到后门需要做DFX,再到我打开内核的源码,我一脸懵逼,这都是啥?
说它不是c吧,这玩意又在.c文件放着,说它是吧,这都是啥,我开始想念多年前那个下天的c语言了。
因为内核和底层是挨着很近的,所以在靠近这个地方,有很多的代码有一些约定成俗的写法,下面一起来瞅瞅?
学了这个,可以帮助我们在阅读内核代码的障碍大大减退,而Linux这谁能避开不用呢?
于是这几个部分就成了面试关键的点。
1、C语言的标准
C语言在1989年发布–>C89或者C90或者ANSI C标准
● K&R C.● ANSI C.● C99.● C11.
K&R
K&R C一般也称为传统C
ANSI C
ANSI C是ANSI在K&R C的基础上进行规范统一,以及一定的拓展。
● 增加了signed、volatile、const关键字。
● 增加了void*数据类型。
● 增加了预处理器命令。
● 增加了宽字符、宽字符串。
● 定义了C标准库。● ……
C99标准
新增了一些关键字,支持新的数据类型。
● 布尔型:_Bool。
● 复数:_Complex。
● 虚数:_Imaginary。
● 内联:inline。
● 指针修饰符:restrict。
● 支持long long、long double数据类型。
● 支持变长数组。
● 允许对结构体特定成员赋值。
● 支持十六进制浮点数、float_Complex等数据类型。
● ……
C11
C11标准是ANSI在2011年发布的最新C语言标准,C11标准修改了C语言标准的一些bug,增加了一些新特性。
包括_Noreturn _Generic等
现在很多编译器还不支持
关于以上不同的编译器支持成都不一样,目前对C99支持最好的是GUN C(99%的特性)
C语言定制
不知道你们有没有发现,平时的C语言和你在玩keil、IAR这些里面的有些不一样。这是因为编译器会在特定的环境下对c语言进行一些拓展。
这个环境包括开发环境、硬件平台、性能优化的需要。
所以在我们需要使用到一些特性的时候,要判断我们使用的编译器是否支持我们的操作哦。
下面就进入正文,关于嵌入式C语言的特性
2、指定初始化
提到C语言中的数组初始化,脑子里:
int a[10] = {0,1,2,3,4,5,6,7};
其中未赋值的会默认为0,但是当我们一个很大的数组,a[10000],这个时候我想赋值第三个和第9998,脑壳痛。
于是C99有了
int b[100] = {[10] = 10, [23] = 21};int b[100] = {[10...20] = 10, [23] = 21};
这样就解决了我们的问题,在结构体中也可以指定赋值。(但是真的感觉还是蛮丑的诶咳咳)
struct student stu1={"wit",20};//旧版struct student stu2=
{.name = "www".age = 99
}//新版
这里在GUN C中…是代表一个范围的意思,这个还可以应用在其他的方面:
switch(i):case 1:case 2...8:default:
3、Linux内核驱动注册
在Linux内核驱动中,有大量使用上面指定初始化方式,通过结构体指定变量来初始化结构体变量。
在驱动程序中,这个file_operations结构体会经常拿来注册我们开发的驱动,然后系统通过回调的方式执行驱动实现。
来来来一起看看这个美丽的结构体:
其实看到这些,不要排斥,一个个的去看,其实还是蛮清晰的。
这些你看一下这些函数名,其实每个有其对应的功能,可能是站一起集合有点壮观,其实分散开就是各自干各自的时候,刚刚开始的时候在一起开个会,安排一下任务。
我们可以看到结构体file_operations里定义了很多结构体成员,而当我们在使用这个驱动时,我们只初始化了部分成员变量。
通过访问结构体的各个成员域来指定初始化,当结构体成员很多时优势就体现出来了,初始化会更加方便。
还有就是因为在工程中,想内核这样的大型项目,在文件中有超级多的地方文件在使用file_operation,如果比如按照顺序,想想你要增加一个或者删除一个,牵一发而动全身啊,怕怕。
第一篇先写到这里,感觉现在大家都不喜欢看很长的东西,喜欢碎片化的,可能是因为节奏太快,生活太忙。
无论如何,希望你开心快乐。
下一篇讲讲Linux内核中的宏,这个可太精彩了。
- 学习资料:《嵌入式C语言自我修养:从芯片、编译器到操作系统》