C编程
从Hello World开始
vim编辑器前边已经介绍过,这里学习一下gcc编译器
gcc [选项] [文件名字]
-c: 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o: <输出文件名>用来指定编译结束以后的输出文件名,如果使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。
-g: 添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编译的时候生成调试所需的符号信息。
-O: 对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进行优化,这样产生的可执行文件执行效率就高。
-O2: 比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
编写代码
使用vim编辑器编写(.c)源代码,在那之前先进行一下vim设置,修改/etc/vim/vimrc文件,文件末尾添加命令,方便C编程。
sudo vi /etc/vim/vimrc
添加内容:
set ts=4 //设置tab制表符为4
set nu //设置行标号
//set noexpandtab
编辑main.c文件,输出hello world!。
编译代码
使用GCC 编译器编译源代码(.c)并链接生为可执行文件(.out)
不同的架构需要不同的gcc编译器,x86架构和arm架构就不同。
gcc main.c -o main //编译+链接生成可执行文件
./main //运行程序
gcc -c main.c //编译
gcc main.o -o main //链接
./main //运行程序
编译流程
GCC 编译器的编译流程是:预处理、编译、汇编和链接。
//源代码(.c)生成目标代码(.o)
预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。
编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。
汇编就是将汇编语言文件编译成二进制目标文件。
//目标代码(.o)和库代码、启动代码链接成可执行文件(.out)
链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。
Makefile的使用
Makefile是一个文件,就是控制gcc编译器**去编译、链接数量较多的源文件。**大大节约了开发时间。
1.首先在工程目录下创建Makefile文件。
2.Makefile文件中格式
目标文件: 依赖文件集合
命令 1
命令 2
……
//命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
//命令即为shell命令
3.使用make命令,make 命令会在当前目录下查找以Makefile(makefile 其实也可以)命名的文件。
4.当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。
Makefile 规则格式
除了 Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile 中是没有意义的,“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时, make 默认的那个目标,它是 Makefile 文件中第一个规则的目标,如果 Makefile 中的第一个规则有多个目标,那么这些目标中的第一个目标就是 make 的“终极目标”。
和python一样 # 为注释
例如:
#Makefile文件内容main为终极目标
1 main: main.o input.o calcu.o
2 gcc -o main main.o input.o calcu.o
3 main.o: main.c
4 gcc -c main.c
5 input.o: input.c
6 gcc -c input.c
7 calcu.o: calcu.c
8 gcc -c calcu.c
9
10 clean:
11 rm *.o
12 rm main
#命令操作
make #生成可执行文件
make clean #清除指定文件
Makefile 变量
问题:如果需要重复的输入文件名会很浪费时间也不容易修改。
解决:Makefile 也支持字符串变量。
1、赋值符“=”
1 name = zzk #zzk赋值给变量name
2 curname = $(name) #$(name)取值
3 name = zuozhongkai #修改变量内容
4
5 print:
6 @echo curname: $(curname)#打印字符
make print
zuozhongkai
“#”作为注释标志,“$”(变量)取字符,
print: @echo 字符串 打印内容,@表示make命令不会打印。
2、赋值符“:=”
1 name = zzk #zzk赋值给变量name
2 curname := $(name) #$(name)取值
3 name = zuozhongkai #修改变量内容
4
5 print:
6 @echo curname: $(curname)#打印字符
make print
zzk
“:=”和“=”的区别就是,“:=”给变量赋值后,该变量得到的字符串就确定了。
curname ?= zuozhongkai
如果变量 curname 前面没有被赋值,那么此变量是“zuozhongkai”
curname:“我没有值,我要你的”
如果前面已经赋过值了,那么就使用前面赋的值。
curname:“我已经有值了,不需要了”
4、变量追加“+=”
objects = main.o inpiut.o
objects += calcu.o
objects 变成了“main.o input.o calcu.o”
5、sinclude 和 include
在 Makefile 中都是读取指定文件内容,这里读取文件
(
s
r
c
t
r
e
e
)
/
a
r
c
h
/
(srctree)/arch/
(srctree)/arch/(ARCH)/config.mk 的内容。 sinclude 读取的文件如果不存在的话不会报错。
6、变量使用规则
$(CONFIG_SYS_ARCH:"%"=%) // 也就是提取CONFIG_SYS_ARCH 里面双引号“”之间的内容。
比如 :CONFIG_SYS_ARCH=“arm”的话,ARCH=arm。
## Makefile 自动化变量
**自动化变量**就是这种变量会把模式中**所定义的一系列的文件**自动的挨个取出,直至**所有的符合模式的文件**都取完。

```bash
1 objects = main.o input.o calcu.o
2 main: $(objects)
3 gcc -o main $(objects)
4
5 %.o : %.c #目标文件.o 依赖文件.c
6 gcc -c $< #所有.c编译成.o
7
8 clean:
9 rm *.o
10 rm main
“%”makefile命令类似于通配符,“$<”自动化变量,所有一系列变量。
Makefile 伪目标
伪目标不代表真正的目标名,通过指定这个伪目标来执行其所在规则的定义的命令。
#如果目录中有clean文件,则会被认为是目标名
clean:
rm *.o
rm main
#这样不怕目录中有clean,明确是伪命令
.PHONY : clean
rm *.o
rm main
Makefile 条件判断
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字有 4 个: ifeq、 ifneq、 ifdef 和 ifndef
ifeq 用来判断是否相等, ifneq 就是判断是否不相等
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’ ,‘<参数 2>’
ifeq “<参数 1>” , “<参数 2>”
#参数即字符
ifdef 用来判断是否相等, ifndef 就是判断是否不相等
ifdef <变量名>
ifndef <变量名>
Makefile 函数使用
Makefile 中的函数是已经定义好的,我们直接使用。
$(函数名 参数集合)
#或者
${函数名 参数集合}
#参数集合之间用“,”隔开
1、函数 subst,用来完成字符串替换
#函数返回被替换以后的字符串
$(subst <from>,<to>,<text>) //将字符串<text>中的<from>内容替换为<to>
#比如:
$(subst zzk,ZZK,my name is zzk) //把字符串“my name is zzk”中的“zzk”替换为“ZZK”
2、函数 patsubst,用来完成模式字符串替换
#函数返回被替换以后的字符串
$(patsubst <pattern>,<replacement>,<text>) //查找字符串<text>中的单词是否符合模式<pattern>,如果匹配就用<replacement>来替换掉
#比如:
$(patsubst %.c,%.o,a.c b.c c.c) //将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”
3、函数 dir,用来提取目录部分
#返回值是文件名序列<names>的目录部分
$(dir <names…>) //从文件名序列<names>中提取出目录部分
#比如:
$(dir </src/a.c>) //提取文件“/src/a.c”的目录部分,也就是“/src”。
4、函数 notdir,去除文件中的目录部分,也就是提取文件名
$(notdir <names…>)
#比如:
$(notdir </src/a.c>) //提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。
5、函数 foreach,用来完成循环
$(foreach <var>, <list>,<text>) //把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text>所包含的表达式
每次< text >都会返回一个字符串,循环的过程中, < tex t>中所包含的每个字符串会以空格隔开,最后当整个循环结束时,
< text >所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。
6、函数 wildcard
问题:%只能用在规则中,不能用于函数。
解决:这就需要wildcard函数。
$(wildcard PATTERN…)
#比如:
$(wildcard *.c) //获取当前目录下所有的.c 文件,类似“%”。
linux的学习就先到这,个人觉得主要还是实践练习,在后期学习的时候再做补充。
7、函数origin,返回值就是变量来源
$(origin <variable>) #variable 是变量名
比如:
$(origin V) //如果变量 V 是在命令行定义的那么它的来源就是"command line",返回command line。
8、filter 函数,过滤函数
$(filter <pattern...>,<text>) //以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,
可以有多个模式。函数返回值就是符合 pattern 的字符串。
比如:
$(filter 4.%,$(MAKE_VERSION)) //保留MAKE_VERSION中的4.%的字符
9、函数 firstword,获取首单词
$(firstword <text>) //取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词。
10、函数shell,执行shell命令
$(shell <command>) //执行命令行的shell脚本