嵌入式linux学习笔记之c编程基础

2019-07-13 00:28发布

c编程基础包括编辑器Vi,编译器gcc,调试器gdb,项目管理器make。(另编辑器emacs,autotools等略)
1文本编辑
Linux提供了一系列功能强大的编辑器,
如vi和Emacs。
1-1   vi 是linux系统的第一个全屏幕交互式编辑器,从诞生到现在一直得到广大用户青睐。        vi有3种工作模式,分别是命令行模式、插入模式、底行模式。
  • 命令行模式:最初进入的一般模式,该模式下可以移动光标进行浏览,整行删除,但无法编辑文字。
  • 插入模式:只有在该模式下,用户才能进行文字的编辑输入,用户可以使用[ESC]键回到命令行模式。
  • 底行模式:该模式下,光标位于屏幕底行,用户可以进行文件保存或退出操作,也可以设置编辑环境,如寻找字符串、列出行号。
1-1-1文本编辑
1. vi hello.c
2. 键入i进入插入模式
3. 编辑
4. 键入[ESC]退入到命令行模式
5. 键入:wq保存退出
1-1-2  命令行模式功能键:
• yy: 复制当前光标所在行 • [n]yy:n为数字,复制当前光标开始的n行 • p: 粘贴复制的内容到光标所在行 • dd:删除当前光标所在行 • [n]dd:删除当前光标所在行开始的n行 • /name:查找光标之后的名为“name”的字符串 • G:光标移动到文件尾(注意是大写) • u: 取消前一个动作(注意是小写)
1-1-3底行模式功能键:
• :w 保存 • :q 退出vi(系统会提示保存修改) • :q! 强行退出(对修改不做保存) • :wq 保存后退出 • :w [filename] 另存为filename的文件 • :set nu 显示行号 • :set nonu 取消行号
1-1-4插入模式功能键:        只有一个,esc退出到命令行模式。 2.GCC( GNU C Compiler)程序编译:将C、C++语言程序、汇编程序编译、链接成可执行文件。GCC编译器能将C、C++语言源程序、汇编程序编译、链接成可执行文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。
2-1     编译过程课细分四步骤:
预处理:Pre-processing 编译:Compiling 汇编:Assembling 链接:Linking
例:使用gcc编译命令,编译hello.c生成可执行文件hello,并运行hello。以下是两种实现方法。

(1)命令: #gcc hello.c   -o  hello
(2)预处理:gcc -E   hello.c  -o   hello.i
          编译:gcc -S   hello.i   -o   hello.s
          汇编:gcc -c  hello.s   -o   hello.o
          链接:gcc     hello.o   -o   hello
             2-2    Gcc通过后缀来区别输入文件的类别:
  •  .c为后缀的文件: C语言源代码文件
  •  .a为后缀的文件: 是由目标文件构成的库文件
  •  .C,.cc或.cxx 为后缀的文件: 是C++源代码文件
  •  .h为后缀的文件: 头文件
  •  .i 为后缀的文件: 是已经预处理过的C源代码文件
  •  .ii为后缀的文件: 是已经预处理过的C++源代码文件
  •  .o为后缀的文件: 是编译后的目标文件
  •  .s为后缀的文件: 是汇编语言源代码文件
  •  .S为后缀的文件: 是经过预编译的汇编语言源代码文件。
语法:gcc 编译器的编译选项要编译的文件名   举例:
hello.c:
#include
int main(void)
{
printf (“Hello world! ”); 
return 0;
}
      编译和运行这段程序:
# gcc hello.c -o hello
# ./hello

 输出:Hello world!
2-3   gcc最基本的用法是∶gcc [options] [filenames]
    • options:编译器所需要的编译选项
    • filenames: 要编译的文件名。
gcc编译器的编译选项大约有100多个,其中多数我们根本就用不到,这里只介绍其中最基本、最常用的参数。
  • -o output_filename:确定可执行文件的名称为output_filename。如果不给出这个选项,gcc就给出预设的可执行文件a.out。(演示)
  • -c:只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件。
  • -g:产生调试工具(GNU的gdb)所必要的符号信息,要想对编译出的程序进行调试,就必须加入这个选项。
  • -O,对程序进行优化编译、链接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
  • -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
  • - l dirname: 将dirname所指出的目录加入到程序头文件目录列表中。
    • c程序中的头文件包含以下两种情况:
    • 1、#include
    • 2、#include"B.h"
    • 对于< >,预处理文件cpp会在系统预设的头文件目录(如/usr/include)中搜寻头文件;对于" " ,cpp在当前的目录中去寻找头文件。
    • 这个选项的作用是告诉cpp,如果当前目录中,没有找到需要的文件,就到指定的dirname目录中去寻找。
    • 例如:gcc foo.c -l /home/include -o foo
  • dirname: 将dirname所指出的目录加入到库文件目录列表中。
    • 默认情况下,连接程序ld在系统设置的预存路径中(如/usr/lib)中搜寻所需的库文件,这个选项的作用是告诉连接程序,首先到就到-L指定的目录中去寻找,然后到系统预设路径中寻找。

  • -lname:在连接时,装载名字为“libname.a”的函数库,该函数库位于系统预设的目录或者由-L选项确定的目录下。例如,-lm表示连接名为“libm.a”的数学函数库。
    • 例:gcc foo.c -L /home/lib -lfoo -o foo
  • -static:静态链接库文件
    • 例:gcc –static hello.c -o hello
    • 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。例如:libhello.so libhello.a。当使用静态库时,连接器找出程序所需的函数,然后将它们拷贝到可执行文件,一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样,动态库会在执行程序内留下一个标记‘指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库。
    • 演示:静态链接与动态链接可执行文件大小比较
  • -Wall:生成所有警告信息
  •  -w:不生成任何警告信息
  •  -DMACRO: 定义MACRO 宏,等效于在程序中使用#define MACRO



3.GDB 程序调试功能: 启动被调试程序
让被调试的程序在制定位置停住
当程序被停住时,可以检查程序状态(如变量值)
启动GDB:
  1. gdb 调试程序名;
  2. gdb ,
file 调试程序名。
使用过程:
  • gcc -g test. c test          //编译生成可执行文件,要带上-g
  • gdb test                         //启动GDB
  • break main                     //在main 函数设置断点
  • run                                 //运行程序
  • next                               //单步运行:
  • continue                         //继续运行
GDB命令
  • list(l)                               //查看程序
  • break(b)                     // 函数名在某函数入口处添加断点
  • break(b)                      //行号在指定行添加断点
  • break(b)                     // 文件名:行号在指定文件的指定行添加断点
  • break(b)                      //行号if 条件当条件为真时,指定行号处断点生效,例b 5 if i=10,当i等于10时第5行断点生效
  • info break                     // 查看所有设置的断点
  • delete                         //断点编号删除断点
  • run(r)                         //开始运行程序
  • next(n)                       // 单步运行程序(不进入子函数)
  • step(s)                        //单步运行程序(进入子函数)
  • continue(c)                      //继续运行程序
  • print(p)                        //变量名查看指定变量值
  • finish                        //运行程序,直到当前函数结束
  • watch                        //变量名对指定变量进行监控
  • quit(q)                        // 退出gdb

4.Makefile 工程管理:使整个软件工程的编译、链接只需要一个命令就可以完成
make在执行时, 需要一个命名为Makefile的文件。Makefile文件描述了整个工程的编译,连接等规则。其中包括:工程中的
哪些源文件需要编译以及如何编译;需要创建那些库文件以及如何创建这些库文件、如何最后产生我们想要得可执行文件。
举例:
hello: main.o func1.o func2.o
gcc main.o func1.o func2.o -o hello
main.o : main.c
gcc –c main.c
func1.o : func1.c
gcc –c func1.c
func2.o : func2.c
gcc –c func2.c
.PHONY : clean
clean :
rm –f hello main.o func1.o func2.o
规则:用于说明如何生成一个或多个目标文件,
规则格式如下:
targets : prerequisites
command
目标依赖命令
main.o : main.c
gcc –c main.c
目标?依赖?命令?
**命令需要以【TAB】键开始**

目标
在Makefile 中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。 一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。
文件名
make命令默认在当前目录下寻找名字为makefile或者Makefile的工程文件,当名字不为这两者之一时,可以使用如下方法指 定:   make –f 文件名

伪目标
Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phonytargets)。 .PHONY : clean clean : rm –f hello main.o func1.o func2.o “.PHONY” 将“clean”目标声明为伪目标

变量
hello: main.o func1.o func2.o gcc main.o func1.o func2.o -o hello 思考1:如果要为hello目标添加一个依赖,如:func3.o,该如何修改? 答案1: hello: main.o func1.o func2.o func3.o gcc main.o func1.o func2.o func3.o -o hello 答案2: obj=main.o func1.o func2.o func3.o hello: $(obj) gcc $(obj) -o hello

在makefile中,存在系统默认的自动化变量
 ^:代表所有的依赖文件
 $@:代表目标
 $<:代表第一个依赖文件
例:
hello: main.o func1.o func2.o
gcc main.o func1.o func2.o -o hello
=》
hello: main.o func1.o func2.o
gcc $^ -o $@
杂项
Makefile中“#”字符后的内容被视作注释。
hello: hello.c
@gcc hello.c –o hello
@:取消回显