Week2学习过程报告

一、学习内容

1. 熟悉Linux系统下的开发环境   
2. 熟悉vi的基本操作   
3. 熟悉gcc编译器的基本原理   
4. 熟练使用gcc编译器的常用选项   
5 .熟练使用gdb调试技术   
6. 熟悉makefile基本原理及语法规范   
7. 掌握静态库和动态库的生成

二、学习记录

1、Linux下C语言编程环境概述

包含:编辑器(vim)、编译链接器(gcc)、调试器(gdb)、项目管理器

2、vi的模式

1)vi的模式:命令行模式、插入模式、底行模式

a.命令行模式:用户可以上下移动光标进行删除字符或者整行删除等,或进行复制、粘贴等,但无法编辑文字。

b.插入模式:用户可以进行文字编辑输入,用户按[esc]可回到命令行模式。

c.底行模式:光标位于屏幕的底行,用户可以进行文件保存或退出操作,也可以设置编辑环境,如寻找字符串、列出行号等。

3、vi的基本流程

(1)进入 vi,即在命令行下键入“vi hello”(文件名)。此时进入的是命令行模式,光标位于屏幕的上方

(2)在命令行模式下键入 i 进入插入模式,如图 3.3 所示。可以看出,在屏幕底部显示有“插入”表示插入模式中的输入状态,在该模式下可以输入文字信息。

(3)最后,在插入模式中,按“Esc”键,则当前模式转入命令行模式,并在底行行中输入“:wq”(存盘 退出)进入底行模式,如图 3.4 所示。
这样,就完成了一个简单的 vi 操作流程:命令行模式→插入模式→底行模式。

4、 vi的各模式功能键

1)命令行模式功能键:

Week2学习过程报告_第1张图片

Week2学习过程报告_第2张图片

2)插入模式功能键:按“Esc”键可回到命令行模式 

3)底行模式功能键:

Week2学习过程报告_第3张图片

:wq!:强制保存并退出
Week2学习过程报告_第4张图片

5、gcc编译器所支持编译源文件的后缀及其解释

Week2学习过程报告_第5张图片 

Week2学习过程报告_第6张图片

6、gcc 编译流程解析:预处理、编译、汇编、链接

Linux的可执行文件并没有像 Windows 那样有明显的.exe后缀名, 只需向其分配x(可执行)权限即可 sudo chmod u+x excutefile

gcc的-E参数可以让gcc在预处理结束后停止编译过程。

将hello.i编译为目标代码,gcc默认将.i文件看成是预处理后的C语言源代码,因此它会直接跳过预处理,开始编译过程。

gcc预处理源文件的时候(第一步),不会进行语法错误的检查。语法检查会在第二步进行,比如花括号不匹配、行末尾没有分号、关键字错误等。

1)预处理阶段:在该阶段,对包含的头文件(#include)和宏定义(#define、#ifdef 等)进行处理。在上述代码的预处理过 程中,编译器将包含的头文件 stdio.h 编译进来,并且用户可以使用 gcc 的选项“-E”进行查看,该选项的 作用是让 gcc 在预处理结束后停止编译过程。

例如:[root@localhost gcc]# gcc –E hello.c –o hello.i

选项“-o”是指目标文件,“.i”文件为已经过处理的 C 程序。

(gcc 指令的一般格式为:gcc [选项] 要编译的文件 [选项] [目标文件] 其中,目标文件可缺省,gcc 默认生成可执行的文件,名为:编译文件.out)

2)编译阶段:接下来进行的是编译阶段,在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看, 该选项只进行编译而不进行汇编,结果生成汇编代码。 

[root@localhost gcc]# gcc –S hello.i –o hello.s 

3)汇编阶段:汇编阶段是把编译阶段生成的“.s”文件转成目标文件,读者在此使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。 

[root@localhost gcc]# gcc –c hello.s –o hello.o 

4)链接阶段:在成功编之后,就进入了链接段。 系统把函数的实现都放到名为 libc.so.6 的库文件中去了,在没有特别指定时, gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 数库中去,这样就能使用各类函数了,而这也正是链接的作用。 

函数库有静态库和动态库两种。静态库是指编译链接时,将库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后名通常为“.a”。动态库与之相反,在编译链接时并没有将库文件的代码加入可执行文件中,而是在程序执行时加载库,这样可以节省系统的开销。一般动态库的后名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。 完成了链接之后,gcc 就可以生成可执行文件。

[root@localhost gcc]# gcc hello.o –o hello 

[root@localhost gcc]# ./hello 

7、gcc 编译选项 

gcc 有超过 100 个可用选项,主要包括总体选项和出错选项、优化选项和体系结构相关选项。

(1)常用选项

Week2学习过程报告_第7张图片

a.“-I dir”:“-I dir”选项可以在头文件的搜索路径列表中添加 dir 目录。由于 Linux 中头文件都默认 放到了“/usr/include/”目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过“-I dir” 选项来指定,这样,gcc 就会到相应的位置查找对应的目录。 

比如在“/root/workplace/gcc”下有两个文件,可在 gcc 命令行中加入“-I”选项:

[root@localhost gcc]# gcc hello1.c –I /root/workplace/gcc/ -o hello1 

gcc 就能够执行出正确结果 。

(在 include 中,<>表在中文件,表在本目 小知识 录中。在上中,可把 hello1.c 的#include<my.h>改为#include “my.h”,

不需要加上-I选了。)

(2)库选项

Week2学习过程报告_第8张图片 

在 Linux 中的每 个程序都会链接到一个或者多个库,函数库有态库和动态库两种,态库是一系列的目标文件(.o 文件)的归文件(文件名格式为 libname.a),如果在编某个程序时链接态库,则链接器将会搜索态库,从中取出它所需要的目标 文件并直接复制到该程序的可执行二进制文件(ELF 格式文件)之中;动态库(文件名格式为 libname.so[.主 版本号.次版本号.发行号])在程序编时并不会被链接到目标代码中,而是在程序运行时才被载入。 

我们所编写的.c文件都可以制作一个函数库。过程如下:

 a.静态库的创建和使用

使用归档工具ar将一些目标文件集成在一起。例如:

[root@localhost lib]# gcc -c haha.c

[root@localhost lib]# ar rcsv libpow.a haha.o

a - haha.o

下面编译主程序,它将会链接到刚生成的静态库haha.a:

[root@localhost lib]# gcc -o heihei heihei.c -L. -lpow

[root@localhost lib]# ./heihei 2 10

2^10=1024

其中,选项“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加 dir 目录,而“-lname” 选项指示编译时链接到库文件 libname.a 或者 libname.so。本实例中,程序heihei.c 需要使用当前目录下的一个静态库 libpow.a。

b.动态库的创建和使用

数显使用gcc的-fPIC选项为动态库创造一个目标文件:

[root@localhost lib]# gcc -fPIC -Wall -c haha.c

接下来使用-shared选项和已创建的位置无关目标代码,生成一个动态库libpow.so

[root@localhost lib]#  gcc -shared -o libpow.so haha.o

下面编译主程序,它将会链接到刚生成的动态库libpow.so

[root@localhost lib]# gcc -o heihei heihei.c -L. -lpow

在运行可执行程序之前,需要注册动态库的路径名。其方法有几种:修改/etc/ld.so.conf 文件,或者修改 LD_LIBRARY_PATH 环境变量,或者将库文件直接复制到/lib 或者/usr/lib 目录下(这两个目录为系统的默认的库路径名)。 

[root@localhost lib]# op libpow.so /lib

[root@localhost lib]# ./heihei 2 10

2^10=1024

动态库只有当使用它的程序执行时才被链接使用,而不是将需要的部分直接编入可执行文件中,并且一 个动态库可以被多个程序使用故可称为共享库,而静态库将会整合到程序中,因此在程序执行时不用加载静态库。 从而可知,链接到静态库会使用户的程序,并且难以升级,但是可能会比较容易部署。而 链接到动态库会使用户的程序轻便,并且易于升级,但是会难以部署。

(3)告警和出错选项

Week2学习过程报告_第9张图片

a.“-ansi”

该选项强制 gcc 生成标准语法所要求的告警信息,尽管这还并不能保证所有没有警告的程序都是符合 ANSI C 标准的。无法发现无效数据类型的错误。如(long long)

b.“-pedantic”

打印ANSI C标准所列出的全部警告信息,同样也保证所有没有警告的程序都是符合ANSI C标准的。 能够查出无效数据类型的错误。

c.

“-Wall”
打印gcc 能够供的所有有用的报警信息。 能够找出未使用的变量,但不能找出无效数据类型的错误。

另外,gcc 还可以利用选项对单独的常见错误分别指定警告。

(4)优化选项

gcc 可以对代码进行优化,它通过编选项“-On”来制优化代码的生成,其中 n 是一个代表优化级别的整数。对于不同版本的 gcc 来讲,n 的取值范围及其对应的优化效果可能并不完全相同,比较典型的是从0变化到2或3。 

不同的优化级别对应不同的优化处理工作。如使用优化选项“-O”主要进行线程跳转(Thread Jump)和 延迟退栈(Deferred Stack Pops)两种优化。使用优化选项“-O2”除了完成所有“-O1”级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令度等。选项“-O3”则还包括循环展开和其他一些与处理器特性相关的优化工作。 

(5)体系结构相关选项 

 

 Week2学习过程报告_第10张图片

8、gdb调试器

gdb 调试器是一款 GNU 开发组织并发布的 UNIX/Linux 下的程序调试工具。

它可以实现:

  1. 启动程序,可以按照用户自定义的要求随心所欲的运行程序。
  2. 可让被调试的程序在用户所指定的调试的断点处停住 (断点可以是条件表达式)。
  3. 当程序停住时,可以检查此时程序中所发生的事。
  4. 动态地改变程序的执行环境。
  5. 从上面来看,gdb和一般的调试工具区别不大,基本上也是完成这些功能,不过在细节上,会发现gdb这个调试工具的强大。大家可能习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。­­­­­­­­­­­­­­­­­­­­­­­­­­­

(1) $ gdb testgdb <---------- 启动gdb

(gdb) break 16 <-------------------- 设置断点,在源程序第16行处。

(gdb) break func <-------------------- 设置断点,在函数func()入口处。

(gdb) info break <-------------------- 查看断点信息。

(gdb) r <--------------------- 运行程序,run命令简写

(gdb) n <--------------------- 单条语句执行,next命令简写。

(gdb) c <--------------------- 继续运行程序,continue命令简写。 Continuing.

(gdb) p i<--------------------- 打印变量i的值,print命令简写。

(gdb) bt <--------------------- 查看函数堆栈。

(gdb) finish <--------------------- 退出函数。

(gdb) c <--------------------- 继续运行。

(gdb) q <--------------------- 退出gdb。

(2)gdb主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数即可。例如:

$ gcc -g hello.c -o hello

$ g++ -g hello.cpp -o hello

如果没有-g,将看不见程序的函数名和变量名,代替它们的全是运行时的内存地址。当用-g把调试信息加入,并成功编译目标代码以后,看看如何用gdb来调试。

启动gdb的方式如下:

  1. gdb <program> program也就是执行文件,一般在当前目录下。
  2. gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后,core dump后产生的文件。
  3. gdb <program> <PID> 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。 gdb启动时,可以加上一些gdb的启动开关,详细的开关可以用gdb -help查看。下面只列举一些比较常用的参数: -symbols <file> -s <file> 从指定文件中读取符号表。 -se file 从指定文件中读取符号表信息,并把它用在可执行文件中。 -core <file> -c <file> 调试时core dump的core文件。 -directory <directory> -d <directory> 加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。

9、makefile

$ vim Makefile

有了这个Makefile,不论什么时候修改源文件,只要执行一下make命令,所有必要的重新编译将自动执行。make程序利用Makefile中的数据,生成并遍历以test为根节点的树;

test(目标文件):prog.o code.o(依赖文件列表)

   tab(至少一个tab的位置) gcc prog.o code.o -o test(命令)

  .......

一个Makefile文件主要含有一系列的规则,每条规则包含一下内容:

一个目标,即make最终需要创建的文件,如可执行文件和目标文件;

目标也可以是要执行的动作,如‘clean’;

一个或多个依赖文件的列表,通常是编译目标文件所需要的其他文件。

之后的一系列命令,是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,并以tab开头(初学者务必注意:是tab,而不是空格)

执行以上Makefile后就会自动化编译

如:

$ make

gcc -c prog.c -o prog.o

gcc -c code.c -o code.o

gcc prog.o code.o -o test

最后就会多产生: porg.o code.o test这三个文件,执行./test查看结果

make clean会执行rm -f *.o test这条命令,完成 clean 操作。

Makefile还可以定义和使用宏(也称做变量),从而使其更加自动化,更加灵活,在Makefile中定义宏的格式为:

macroname = macrotext

使用宏的格式为:

$(macroname)

================================================================

实验楼操作笔记:

1、从教程vimtutor中退出只需输入":q!"

2、h:光标左移,l:光标右移,j:光标下行,k:光标上行

3、x:删除光标处字符

4、i:在光标处前一个位置插入字符

5、esc:恢复为正常状态

6、a:在光标位置输入文本

7、wq:保存文本后并退出

8、dw:删除以光标所在位置开头的单词

9、d$:删除从光标处直至末尾的部分文本

10、删除讲解:

Week2学习过程报告_第11张图片

11、dd:删除一整行;2dd:删除两整行

12:u:撤销上一次操作;U:撤销一整行全部操作;Ctrl-R:撤销撤销动作

13、dd删除后的句子会缓存至vim中,用p在欲插入粘贴的位置上方课将上一次剪切的句子贴入

14、r:用光标指向修改部位,r,然后输入欲改为的字符。完成替换

15、c$:更正至光标位置起到句末的部分

16、shift-g:跳转至指定行;Ctrl-g:查看文件信息和当前信息

17、/+字符:自动在文本中向下搜索关键词,?+字符:自动在文本中向上搜索关键词,n向后继续查找。Shift-n为向上查找。

18、%:括号匹配查看

19、:s/old/new:用new替换文本中第一个相符字符串;:s/old/new/g:替换整行中的相符字符串;#,#s/old/new/g:替换两行间的匹配串;:%s/old/new/g:替换整个文件中的匹配串;:%s/old/new/gc:进行全文替换时需询问用户确认

20、Shift+zz:保存退出vim

21、行间转换:

Week2学习过程报告_第12张图片

 

22、行内转换:

Week2学习过程报告_第13张图片

23、~:将小写字母变为大写

24、复制粘贴和剪切:

Week2学习过程报告_第14张图片

25、ddp:交换上下行

26、替换和撤销:

Week2学习过程报告_第15张图片

27、使用命令进行快速调整缩进操作

Week2学习过程报告_第16张图片

28、shiftwidth命令

shiftwidth命令是指>>命令产生的缩进(可以简写成sw) 普通模式下输入:进入命令行模式下对shiftwidth值进行设置可以控制缩进和回退的字符数获取目前的设定值

:set shiftwidth?查看缩进值默认值;:set shiftwidth=n设置缩进值

29、设置文本位置

命令行模式下输入:ce(center)命令使本行内容居中

命令行模式下输入:ri(right)命令使本行文本靠右

命令行模式下输入:le(left)命令使本行内容靠左

30、高级查找

Week2学习过程报告_第17张图片

31、同时创建两个新文件并编辑:$ vim 1.txt 2.txt

默认进入1.txt文件的编辑界面

Week2学习过程报告_第18张图片

进入vim后打开新文件

Week2学习过程报告_第19张图片

恢复文件:vim -r进入文档后,输入:ewcover 1.txt

31、可视模式选取

Week2学习过程报告_第20张图片

32、视窗操作

:new 打开一个新的vim视窗,并进入视窗编辑一个新文件

Week2学习过程报告_第21张图片

33、文档加密:$ vim -x file1

34、在vim执行外部命令:在命令行模式中输入!可以执行外部的shell命令

Week2学习过程报告_第22张图片

35、vim中的查看帮助

Week2学习过程报告_第23张图片

36、vim的功能设定:可以在编辑文件的时候进行功能设定,如命令行模式下输入:set nu(显示行数),设定值退出vim后不会保存。要永久保存配置需要修改vim配置文件。 vim的配置文件~/.vimrc,可以打开文件进行修改,不过务必小心不要影响vim正常使用

37、获取目前的设定

Week2学习过程报告_第24张图片

38、set功能的说明

Week2学习过程报告_第25张图片

39、vim进入编译器后并不会打开任何文件,但是可以通过:e 文件路径进入某指定文件

40、I:在行首插入

41、A:在行末插入

42、o:在当前行后插入一个新行;O:在当前行前插入一个新行

43、X:删除游标所在前一个字符

44、d^:删除至行首

45、dG:删除到文档结尾处;dlG删除至文档首部

46、.表示重复上一次的命令操作

47、Ctrl+o:跳转回上次光标的位置

 

=============================================

遇到的问题:

1、在vim教程中,想练习:wq保存文件后退出时,总是将命令错误输入在如下图的小框内,然后后来使用:q!退出小框后再次输入:wq<Enter>后就成功了。

Week2学习过程报告_第26张图片

2、在Linux实验GCC的使用这一节中,最后让我们试编译hello.h、hello_print.c、hello_main.c三个文件时,输入$gcc hello_print.c hello_main.c -o hello会报错,如下图:

Week2学习过程报告_第27张图片

我尝试在hello_main.c中加入#include<stdio.h>,不再报错。但是却没有输出“Hello,Shi-Yan-Lou”。

后来我删掉了以上修改,重新编译,却又不报错了。我觉得很奇怪。而且也依旧没有输出。

3、makefile中按照实验指导操作却总是有报错,无法得出自动编译结果,频频出现“未定义调用myfun()"这样的提示。

 

 

你可能感兴趣的:(Week2学习过程报告)