10、Linux C编程
编辑一个程序,一般可以分为编辑+编译两个过程,就像在开发STM32时,一般都是使用Keil完成这两项工作,这种软件也被叫做IDE(集成开发环境),而在Linux下,没有这种IDE,在 Linux 下这两部分是分开的,比如我们用 VIM 进行代码编写,编写完成以后再使用 GCC 编译器进行 编译。在后续,采用VScode进行编辑,而本节依旧采用VIM进行编辑。
在使用VIM编辑器前,需要先设置一下VIM编辑器。
用 vi 打开文件/etc/vim/vimrc,在此文 件最后面输入如下代码:
set ts=4
set nu
将Tab键设置为4个空格并显示行数。
然后使用vi编辑器创建一个main.c文件,并输入以下内容:
完成了编写的任务后,使用gcc编译器进行编译
在执行完gcc main后,将产生一个名称为a.out的文件。
gcc编译同样具有报错功能,当输入的代码有误,将会出现提示信息。
程序编译的四个过程:
1、预处理:条件编译,头文件包含,宏替换的处理,生成.i文件。
2、编译:将预处理后的文件转换成汇编语言,生成.s文件
3、汇编:汇编变为目标代码(机器代码)生成.o的文件
4、链接:连接目标代码,生成可执行程序
11、makefile
11.1 makefile简介
在使用gcc对文件进行编译时,当文件数量较少时确实较为方便,但一旦文件数量过多,因为gcc编译每一次都会将所有文件编译一遍,即使这些文件没有被修改,那么将会大大增加编译的时间。所以编译的最好的方法当然是哪个文件被修改,就对这个文件进行编译,其他未被修改的文件就不需要再重新编译。
基于上述目标,就提出了使用makefile来生成可执行文件,来开下面这段代码:
首先,第一行中,main文件的生成依赖于main.o、input.o、calcu.o三个文件,当makefile执行时,如果发现系统中没有这些.o文件,就会在makefile中搜寻是否有生成这些.o文件的语句,可以看到,3~8行就负责生成这些.o文件,如main.o:main.c语句,就表示main.o文件依赖于main.c文件生成。
makefile文件创建好后,输入make指令,就将自动执行makefile内的语句,分别创建.o文件
修改input.c文件后,再使用make语句重新编译,此时只有input.c被重新编译,这就实现了上面所说的功能。
11.2 makefile基本语法
makefile的规则格式如下:
例如,下面的这条规则:
这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新 目标 main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也 必须更新,“更新”就是执行一遍规则中的命令列表。
总结make的执行过程:
1、make命令在当前目录下查找以Makefile命名的文件。
2、在找到Makefile文件后,按照makefile中定义的规则去编译生成最终的目标文件。,
3、如果目标文件不存在,或者目标所依赖的文件比目标新,就会执行后面的命令来更新目标。
makefile同样支持变量,通过使用变量,在编程时就不需要输入繁琐的文件名称,makefile中变量使用方法如下:
Makefile 中变量的引用方法是“$(变量名)”
makefile中的赋值可以使用三种赋值符:
1、赋值符“=”
使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值,也就是变量的真实值取决于它所引用的变量的最后一次有效值。
当执行make print后,输出的结果是zhouxuehang。
2、赋值符“:=”
:=就与上面的=不同,它不会使用后面定义的变量,只会使用前面以及定义好的。
3、赋值符“?=”
?=的特性相当有趣,当前面没有给curname赋值时,curname的值就等于当前值。
如果在前面已被赋值,那么curname就等于之前的值。
makefile的模式规则:
在上面对makefile文件进行编写时,每一个 C 文件都要写一个对 应的规则,如果工程中 C 文件很多的话显然不能这么做。为此,我们可以使用 Makefile 中的模 式规则,通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件。
在模式规则中,%就类似于通配符,比如%.c就代表所有以.c结尾的文件,使用方法如下:
但单纯的替换并不能直接使用,因为此时命令还没有写,而为了解决命令的问题,引入了自动化变量:
上面讲的模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候 都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生 成对应的目标?自动化变量就是完成这个功能的!所谓自动化变量就是这种变量会把模式中所 定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该 出现在规则的命令中。
使用自动化变量$<替换后,代码如下:
makefile伪目标
Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代 表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。
打个比方,在上面的例子中,我们有一个名为clean的规则,该规则一旦被make调用,就会清除文件夹中的.o文件以及main文件,但如果我们在该文件夹内,创建了一个名为clean的文件,此时,使用make clean,就不会实现我们想要的功能,
可以看到,在上图中,clean命令没有被执行。
为此,可以使用伪目标来定义该规则:
声明的格式如下:
修改后的代码如下:
12、shell脚本
12.1 shell脚本基础操作
shell脚本类似windows的批处理文件,shell脚本就是将连续执行的命令写成一个文件。
shell脚本提供数组、循环、条件判断的等功能。shell脚本一般是Linux运维或者系统管理员要掌握的,作为嵌入式开发人员,只需要掌握shell脚本最基础的部分即可。
可以使用read来编写交互式shell脚本,程序如下:
shell仅支持整形,当需要使用表达式时,使用$((表达式))。
在shell脚本中,可以使用test命令来查看文件是否存在、文件权限等。
&&和||命令:
cmd1 && cmd2 当cmd1执行完并且正确,那么cmd2开始执行,如果cmd1执行完毕错误,那么cmd2不执行。
cmd1 || cmd2 当cmd1执行完毕并正确,那么cmd2不执行,反之cmd2执行。
shell中当需要进行判断时可以使用中括号判断符,但具有诸多限制:中括号内只能使用 == 和 !=两种判断符;字符串必须加上双引号;中括号前后必须空一格。
12.2 shell脚本条件判断、函数和循环
shell脚本支持条件判断,虽然可以通过&&和||来实现简单的条件判断,但是稍微复杂一点的场景就不适合了。shell脚本提供了if then条件判断语句,写法
if 条件判断 ; then
//判断成立要做的事情
fi
还有if then else 语句,写法
if 条件判断 ; then
//条件判断成立要做的事情
else
//条件判断不成立要做的事情。
fi
或:
if 条件判断 ; then
//条件判断成立要做的事情
elif [条件判断]; then
//条件判断成立要做的事情
else
//条件判断不成立要做的事情。
fi
最后还有case语句
case $变量 in
“第1个变量内容”)
程序段
;; //表示该程序块结束!!
“第2个变量内容”)
程序段;;
“第n个变量内容”)
程序段
;;
esac
shell脚本也支持函数,函数写法如下:
function fname () {
//函数代码段
}
shell脚本也支持自定义函数,格式如下:
function fname () {
//函数代码段
}
但需要注意的是,在shell脚本内的传参不需要括号。
shell脚本同样支持循环:
while [条件] //括号内的状态是判断式
do //循环开始
//循环代码段
done
还有另外一种until do done,表示条件不成立的时候循环,条件成立以后就不循环了,写法如下:
until [条件]
do
//循环代码段
done
for循环,使用for循环可以知道有循环次数,写法
for var in con1 con2 con3……
do
//循环代码段
done
for循环数值处理,写法
for((初始值; 限制值; 执行步长))
do
//循环代码段
done