预处理: cpp预处理器, 去掉注释, 展开头文件, 宏替换
gcc -E test.c -o test.i
编译: gcc, 将源代码文件编译成汇编语言代码
gcc -S test.i -o test.s
汇编: as, 将汇编语言代码编译成了二进制文件(目标代码)
gcc -c test.s -o test.o
链接: ld, 链接test.c代码中调用的库函数
gcc -o test test.o
-v
:查看gcc版本号, --version也可以-E
:生成预处理文件-S
:生成汇编文件-c
:只编译,生成.o文件, 通常称为目标文件-I
:指定头文件所在的路径-L
:指定库文件所在的路径-l
:指定库的名字-o
:指定生成的目标文件的名字-g
:包含调试信息使用gdb调试需要添加-g参数-On
:n=0∼3,编译优化,n越大优化得越多库是二进制文件, 是源代码文件的另一种表现形式, 是加了密的源代码; 是一些功能相近或者是相似的函数的集合体。
头文件:包含了库函数的声明
库文件:包含了库函数的代码实现
库不能单独使用, 只能作为其他执行程序的一部分完成某些功能, 也就是说只能被其他程序调用才能使用
库可分静态库(static library)和共享库(shared library)
一些目标代码的集合,在可执行程序运行前,就已经加入执行码中,成为执行程序的一部分(编译后删除.a无影响)
前缀lib
,后缀.a
制作
gcc -c fun1.c fun2.c
ar rcs libtest1.a fun1.o fun2.o
使用
头文件要引用
gcc -o main main.c
-I 头文件路径
-L .a文件路径
-l 库名(只要中间,不带lib和.a)
main.c与head.h和libtest1.a在同一级目录的情况:gcc -o main1 main.c -I./ -L./ -ltest
main.c与head.h和libtest1.a在不同一级目录的情况:gcc -o main1 main.c -I./include -L./lib -ltest1
优缺点:
lib
,后缀.so
gcc -fpic -c fun1.c fun2.c
gcc -shared fun1.o fun2.o -o libtest2.so
nm
命令可以查看.so库中有哪些函数目标:依赖
(tab)命令
三要素:
main:main.c fun1.c fun2.c sum.c
gcc -o main main.c fun1.c fun2.c sum.c -I./
缺点:效率低,修改一个文件, 所有的文件会全部重新编译
Makefile注释:#
多行前插入#:Ctrl+V进入列模式,hjkl移动选定,大I(shift+I)插入,#,两次ESC
Makefile工作原理:
基本原则:若想生成目标, 检查规则中的所有的依赖文件是否都存在
如果有的依赖文件不存在, 则向下搜索规则, 看是否有生成该依赖文件的规则
如果所有依赖都存在, 检查规则中的目标是否需要更新, 必须先检查它的所有依赖,依赖中有任何一个被更新, 则目标必须更新.(检查的规则是哪个时间大哪个最新)
main:main.o fun1.o fun2.o sum.o
gcc -o main main.o fun1.o fun2.o sum.o
main.o:main.c
gcc -o main.o -c main.c -I./
fun1.o:fun1.c
gcc -o fun1.o -c fun1.c
fun2.o:fun2.c
gcc -o fun2.o -c fun2.c
sum.o:sum.c
gcc -o sum.o -c sum.c
缺点:冗余, 若.c文件数量很多, 编写起来比较麻烦
Makefile中的变量:
类似于C语言中的宏定义, 使用该变量相当于内容替换, 使用变量可以使makefile易于维护, 修改起来变得简单
变量分三种:普通变量、自带变量、自动变量
普通变量
=
:foo = abc
$(变量名)
:bar = $(foo)
自带变量:makefile中也提供了一些变量(变量名大写)供用户直接使用, 我们可以直接对其进行赋值
CC
= gcc #arm-linux-gccCPPFLAGS
: C预处理的选项 -ICFLAGS
: C编译器的选项 -Wall -g -cLDFLAGS
: 链接器选项 -L -l自动变量:只能在规则命令中使用
$@
: 表示规则中的目标$<
: 表示规则中的第一个条件$^
: 表示规则中的所有条件, 组成一个列表, 以空格隔开, 如果这个列表中有重复的项则消除重复项。模式规则:用%,%.o
,%.c
target=main
object=main.o fun1.o fun2.o sum.o
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ -c $< $(CPPFLAGS)
wildcard
:查找指定目录下的指定类型的文件,src=$(wildcard *.c)
,找到当前目录下所有后缀为.c的文件,赋值给srcpatsubst
:匹配替换,obj=$(patsubst %.c,%.o, $(src))
,把src变量里所有后缀为.c的文件替换成.osrc=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ -c $< $(CPPFLAGS)
PHONY:clean
,声明目标为伪目标之后, makefile将不会检查该目标是否存在或者该目标是否需要更新-
:此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”@
:不显示命令本身, 只显示结果。如:“@echo clean done”src=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ -c $< $(CPPFLAGS)
.PHONY:clean
clean:
-rm -f $(target) $(object)
GDB(GNU Debugger)是GCC的调试工具,主要帮你完成下面四个方面的功能:
首先在编译时, 我们必须要把调试信息加到可执行文件中,使用编译器(cc/gcc/g++)的`-g`参数,如果没有`-g`,你将看不见程序的函数名、变量名。所代替的全是运行时的内存地址。
gdb+程序
,执行gdb进入gdb环境set args
,如:set args 10 20 30 40 50show args
run
:程序开始执行, 如果有断点, 停在第一个断点处start
:程序向下执行一行。(在第一条语句处停止)list
命令显示源代码,默认10行list linenum
:打印第linenum行的上下文内容.list function
:显示函数名为function的函数的源程序。list
: 显示当前行后面的源程序。list -
:显示当前文件开始处的源程序。list file:linenum
: 显示file文件下第n行list file:function
: 显示file文件的函数名为function的函数的源程序break
设置断点, 可以简写为b
b 10
设置断点, 在源程序第10行b func
设置断点, 在func函数入口处b filename:linenum
在源文件filename的linenum行处停住b filename:function
在源文件filename的function函数的入口处停住info b
== info break
== i break
== i b
b test.c:8 if intValue == 5
delete
可简写为d
delete num
delete num1 num2 ...
delete m-n
delete
disable
简写为dis
。不会删除,要用时可enable
disable num
disable num1 num2 ...
disable m-n
disable
enable
简写为ena
enable num
enable num1 num2 ...
enable m-n
disable/enable
run
运行程序, 可简写为r
next
单步跟踪, 函数调用当作一条简单语句执行, 可简写为n
step
单步跟踪, 函数调进入被调用函数体内, 可简写为s
finish
退出进入的函数, 如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
until
在一个循环体内单步跟踪时, 这个命令可以运行程序直到退出循环体,可简写为u,
如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
continue
继续运行程序, 可简写为c(若有断点则跳到下一个断点处)
print
打印变量、字符串、表达式等的值, 可简写为p
display
变量名info display
:查看display设置的自动显示的信息。undisplay num
(info display时显示的编号)delete display dnums
:删除自动显示, dnums意为所设置好了的自动显式的编号。如果要同时删除几个, 编号可以用空格分隔, 如果要删除一个范围内的编号, 可以用减号表示disable display dnums
:使自动显示无效enable display dnums
:使无效自动显示有效ptype width
:查看变量width的类型p width
:打印变量width的值set var width=47
:将变量var值设置为47此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。