本实验用到的软件为ubunto10.04,VMware Workstation8,也安装了VMtools。可以自行选择较高版本的软件。!!
实验一 Linux系统安装与简单配置
一、实验目的
1.掌握Linux系统安装的分区准备。
2.掌握Linux系统的安装步骤。
3.掌握Linux系统分区的挂载和卸载。
4.掌握Linux系统的启动和关闭操作。
二、实验内容
1.安装VMware虚拟机,设置光盘驱动器,为Linux系统安装做准备。
2.在虚拟机下安装Linux操作系统(如Ubuntu桌面版本)和VMwareTool,实现宿主机和虚拟机之间的文件拷贝。
3.配置Linux系统运行环境。
4.增加一块SCSI硬盘,请在新增的硬盘中给出系统6个分区的方案,并选择一种方案利用fdisk进行分区,并且学会使用命令建立和删除交换分区。
5.将新的Linux系统分区挂载到系统中;卸载新挂载的分区,重新挂载到目录树中的其他位置。
6. 修改配置文件将分区配置成开机自动挂载。
三、主要的实验步骤
1.制定安装系统的分区计划。
2.配置光驱引导镜像文件iso,启动系统,开始安装过程。
3.根据安装计划,对磁盘空间进行分区设置(一个主分区、一个swap分区,一个空闲分区)。
4.根据系统安装指导,完成Linux系统的安装过程。
5.安装成功后,退出系统,重新启动虚拟机,登陆Linux操作系统。
6.对Linux系统进行配置,如VMwareTool,网络设备等。
7.利用fdisk分区工具依据设计的将硬盘分成5个分区的方案,进行分配。并对分区采用mkfs命令对分区进行格式化。
8.利用partprobe命令重新加载分区表。利用df -h命令可查看分区挂载情况。
9.利用mkswap命令创建交换分区,并使用swapon命令激活交换分区。
10.利用磁盘使用工具和mount,将新创建的Linux系统分区挂载到系统中。将新挂载的分区卸载,并重新挂载到目录树的其他位置。观察挂载之前和之后的该目录下所存储的文件。
11.利用/ect/fstab配置文件进行分区的自动挂载,重启测试。
四、拓展实验
1. 设计方案,在计算机或虚拟机(二选一)中安装双系统?并通过实验验证自己的方案。
- 计算机(宿主机)上安装双系统:提示可能用到的工具:多系统启动维护工具EasyBCD,虚拟光驱(如:Daemon Tools)等。
- 虚拟机上安装双系统:可参考以下链接,
https://blog.youkuaiyun.com/GH_12138/article/details/123644520。
2. 新建一个虚拟机,安装另外一个版本的Linux系统,如:CentOS、Redhat等,体验Linux不同发行版的使用环境。
五、实验结果
1.在实验之前要先学会如何卸载VMware虚拟机。
(1)在服务或任务管理器中停止运行VMware相关的进程
(2)在控制面板中卸载VMware Workstation
图1-1 服务中的VMware相关程序
图1-2 任务管理器中的VMware相关程序
(3)清理VMware虚拟机在注册表中的信息和遗留在电脑中的文件
图1-3 注册表中的VMware相关文件
(4)清理我的电脑中的VMware文件
2.安装VMware虚拟机
图1-4 安装虚拟机—命名
图1-5 安装虚拟机—自定义硬件
3.分区操作
(1)新建主分区(10个G)挂载点为根
图1-5 新建主分区作为系统盘
(2)新建交换分区,分配2个G
图1-6 新建交换分区
图1-7 分区设置
4.安装VMware-tools
图1-8 VMware-tools安装成功
5.分区操作
(1)利用fdisk-p命令查看分区情况
(2)我们发现sda2和sda5的起始地址和结束地址分别都是柱面1216和柱面1459,说明了交换分区是在扩展分区下面扩展出来的,并且扩展分区的空间全部分配给了交换分区,因此无法在扩展分区上进一步划分新的分区。我们将两个分区全部删除,重新划分。
(3)利用fdisk-n命令新建扩展分区2,如图1-11.
(4)创建扩展分区后由于只能有一个扩展分区,我们在扩展分区上新建5个逻辑分区。加上系统盘主分区,总共六个分区。最后利用fdisk-w命令保存分区,分区操作完成。如图1-12。重启系统,查看磁盘分区情况,如图1-13
图1-9 fdisk-p命令
图1-10 fdisk-d命令
图1-11 fdisk-n命令
图1-12 fdisk-w命令
图1-13 磁盘分区情况
(5)新创建五个分区还没有格式化,我们运用 sudo mkfs -c -t ext4 /dev/sda5 (mkfs是格式化命令,-c是检测磁盘非必要,-t必要,ext4指定格式化成ext4文件系统)。同时我们需要运用mount命令把分区挂载到目录树当中,使能够通过目录树访问磁盘。
图1-14 分区挂载情况
6.创建交换分区
我们的分区还有空闲部分,我们新建逻辑分区或者主分区,并把它转换成交换分区。
- 利用fdisk-n命令新建逻辑分区sda10
- 利用fdisk-t命令选择你想要转换的分区号(sda10),并通过L来查看可以转换成哪些分区,这里是82—交换分区
图1-15 fdisk-t 转换分区命令
(3)转换完毕之后用w命令保存,创建完或者说转换完交换分区我们应该如何使用?这就需要格式化它并且激活它。我们用sudo partprobe命令
重新读取分区表,再用sudo mkswap /dev/sda10 格式化swap交换分区,最后用sudo swapon /dev/sda10激活该分区。swapon -s 命令可以查看激活情况。
图1-16 创建并激活交换分区
图1-17 交换分区主要命令
- 激活了之后还需要自动挂载,不然再次重启后我们需要手动挂载。
我们使用 sudo gedit /etc/fstab 命令打开该配置文件并进行编辑。
图1-18 /etc/fstab介绍
图1-19 /etc/fstab配置文件
7.测试:利用磁盘使用工具和mount,将新创建的Linux系统分区挂载到系统中。将新挂载的分区卸载,并重新挂载到目录树的其他位置。观察挂载之前和之后的该目录下所存储的文件。
(1)在之前的步骤中我们已经将sda9挂载到/home/sda9这个文件夹下,我们在这个文件夹下面新写一个testfile.txt文件
图1-20 新写一个testfile.txt文件
(2)我们使用umonut命令将这个文件解挂(卸载)掉
图1-21 解挂
(3)上图可以看出已经解挂了,并且/home/sda9文件夹下面的全没了。
图1-22 重新挂载
这个时候挂载到新建的另一个文件夹上去,发现又有了。说明解挂只是将文件系统从目录树中移除,并不会删除分区或其中的数据。
拓展试验:
图1-23 三系统
Ubunto10.04
Windows XP
CentOS 7
实验二 Linux常用命令使用
一、实验目的
1.掌握Linux一般命令格式。
2.掌握有关文件和目录操作的常用命令。
3.熟练使用man命令。
二、实验内容
1.熟悉cd、date、pwd、cal、who、echo、clear、passwd等常用命令。
2.在用户主目录下对文件进行操作:复制一个文件、显示文件内容、查找指定内容、排序、文件比较、文件删除等。
3.对目录进行管理:创建和删除子目录、改变和显示工作目录、列出和更改文件权限等。
4.利用man命令显示date、echo等命令的手册页。
5.利用ps命令显示系统中的进程信息。
三、主要实验步骤
1.登陆系统,使用passwd命令修改密码为123456,并重新登录系统。
2.使用简单命令:date、cal、who、echo、clear等,了解Linux命令格式。
3.浏览文件系统:
- 运行pwd命令,确定当前工作目录。
- 运行ls –l命令,理解各字段含义。
- 运行ls –ai命令,理解各字段含义。
- 使用cd命令,将工作目录改到根(/)上。运行ls –l命令,结合教材中图2.2,了解各个目录的作用。
- 直接使用cd,通过pwd指令验证目录位置。
- 用mkdir建立一个子目录subdir。
- 将工作目录更改到subdir。
4.文件操作:
- 验证当前工作目录在subdir。
- 运行date>file1,然后运行cat file1,看到什么信息?
- 运行cat subdir,会出现什么结果?为什么?
- 利用man命令显示date命令的使用说明。
- 运行man date>>file1,看到什么信息?运行cat file1,看到什么信息?
- 显示file1的当前10行,后19行。
- 运行cp 文件名1 文件名2,然后ls –l,看到什么信息?运行mv 文件名2 文件名3,然后ls –l,看到什么信息?运行cat 文件名,结果如何?
- 运行rm 文件名3,然后ls –l,结果如何?
- 在/etc/passwd文件中查找合适你的注册名的行。
- 运行ls –l,理解各文件的权限是什么?
- 用两种方式改变file1的权限。
- 统计file1文件的行数、字数。
- 运行cat 文件名|wc -l,结果如何?
5.权限管理
假设目前要开发一个项目叫做LinuxDemo,参与人包括:zhao, qian, sun, li, zhou, wu六人,这六人的分组为如图1所示。请利用所学命令构造满足如下要求的用户权限模型。
具体要求如下:
0) 使用图1中的分组创建组,并将相应的学生添加到相应分组
1) 所有目录都保存在同一的文件夹下/LinuxDemo
2) 每个分组拥有独立的文件夹
3) 不同组之间不可访问各自的文件夹
4) 每个学生在所在组的文件夹下拥有一个所属的文件夹
5) 同组不同学生之间可以查看各自文件夹的内容,但不可以修改,学生只能修改自己的文件内容
6) 请设计测试用例,查看所设计的权限模型是否满足要求。
分组 | 学生 |
designing | zhao qian |
coding | sun li |
testing | zhou wu |
图1 LinuxCourse
6.进程管理
开启多个终端程序,使用ps命令是查看进程状态,并用kill命令结束其中一个终端程序。
7.文件压缩和解压
利用gzip命令对某个文件或文件夹进行压缩,然后再对其解压。使用unzip命令对Windows下生成的zip格式的压缩文件进行解压缩。
四、实验结果
1. 登陆系统,使用passwd命令修改密码为123456,并重新登录系统。(如图2-1)
2. 使用简单命令:date、cal、who、echo、clear等,了解Linux命令格式。(如图2-2)
图2-1 修改密码
图2-2 简单命令
3.浏览系统文件
(1)运行pwd命令,确定当前工作目录。
图2-3 pwd
(2)运行ls -l命令,理解各字段含义
图2-4 ls -l
就拿第一行来说:(从左到右)
“-”表示普通文件
权限:所有者可读可写(rw-),组、其他用户只读(r--)
1代表硬链接数为1(硬链接是多个文件名指向同一个inode的不同目录条目)
两个rc分别代表所有者和所有组
文件大小是60215221字节(差不多57.4MB)
最后修改时间是2011年11月14日 12:05
文件名是VMwareTools-8.8.1-528969.tar.gz
(读是r,写是w,x是执行,d开头说明该项为目录)
- 可列出内容(r)
- 可创建/删除文件(w)
- 可进入目录(x)
(3)运行ls –ai命令,理解各字段含义。
521264 .gnome2_private
前面的数字是当前目录的inode号 后面的是文件名或目录名,如果加上一个点说明该文件或目录是隐藏的
图2-5 ls -ai
(4)使用cd命令,将工作目录改到根(/)上。运行ls –l命令,结合教材中图2.2,了解各个目录的作用。
图2-6 根目录
bin 目录存放着基础命令的二进制文件
boot目录存储着系统启动文件
dev是设备文件接口
etc是全局配置文件中心
lib是核心共享库文件
home是普通用户主目录
root是超级用户root的主目录
lost+found 是文件系统修复后的碎片恢复区
mnt/media 是临时挂载点
proc是内核与进程的虚拟文件系统
sys是硬件设备的配置接口
tmp是存储临时文件
var是存储可变数据
opt是第三方独立软件安装目录
usr是用户级程序与文档
sbin是系统管理命令(需要root权限)
selinux存放着SELinux的安全策略文件
srv 存储服务数据
cdrom是为传统挂载点
- 直接使用cd,通过pwd指令验证目录位置
图2-7 home目录
(6)用mkdir建立一个子目录subdir,并将工作目录更改到此。
图2-8 mkdir命令
4. 文件操作:
(1)验证当前工作目录在subdir。
(2)运行date>file1,然后运行cat file1,看到什么信息?
(3)运行cat subdir,会出现什么结果?为什么?
如上图所示,出现了没有这个文件或者目录。这个原因是因为date命令的作用是显示或设置系统日期和时间,重定向到file1文件当中,文件内容会是当前的日期时间信息。而date命令只是输出日期时间信息,它不会创建目录,只是创建文件。如果用户想要保存到某个目录下的文件,需要确保该目录存在,或者使用正确的路径。而cat命令是用来查看文件内容的而不是目录。目录需要用ls命令查看。为什么系统报错是因为cat无法处理目录,是因为你在subdir里面查subdir当然找不到了你又没有再创建一个subdir目录,真的这个查了我半天,我退回到上一级才发现是有这个文件。
(4)利用man命令显示date命令的使用说明。
图2-8 man date命令
(5)运行man date>>file1,看到什么信息?运行cat file1,看到什么信息?
前者啥都没看见,后者看到了date命令的使用说明。(在终端命令行里没在文件里)
(6)显示file1的当前10行,后19行。
图2-9 head tail命令
(7)运行cp 文件名1 文件名2,然后ls –l,看到什么信息?运行mv 文件名2 文件名3,然后ls –l,看到什么信息?运行cat 文件名,结果如何?
Cat文件名看到的是file1里面的所有内容。
运行rm 文件名3,然后ls –l,结果如何?
删掉了呗,没了呗。
(8)在/etc/passwd文件中查找合适你的注册名的行。
(9)运行ls –l,理解各文件的权限是什么?同上
(10)用两种方式改变file1的权限。
分别是数值模式和符号模式
chmod 755 file1
作用:
通过 八进制数字模式 将文件 file1 的权限设置为:
- 所有者 (u):rwx(读、写、执行)
- 所属组 (g):r-x(读、执行,无写权限)
- 其他用户 (o):r-x(读、执行,无写权限)
chmod u+x,g-w file1
作用:
通过 符号模式 进一步调整权限:
- **u+x:给文件所有者 添加执行权限**(即使已有)
- **g-w:从文件所属组 移除写权限**(如果存在)
权限变更解析:
- 所有者 (u):确保执行权限存在(可能无实际变化)
- 所属组 (g):若组有写权限(如 rw-),会变成 r--;若原本无写权限(如 r-x),则保持不变
(11)统计file1文件的行数、字数。
行、词数、字节
(12)运行cat 文件名|wc -l,结果如何?、
只统计行数
5.权限管理
假设目前要开发一个项目叫做LinuxDemo,参与人包括:zhao, qian, sun, li, zhou, wu六人,这六人的分组为如图1所示。请利用所学命令构造满足如下要求的用户权限模型。
具体要求如下:
0) 使用图1中的分组创建组,并将相应的学生添加到相应分组
1) 所有目录都保存在同一的文件夹下/LinuxDemo
2) 每个分组拥有独立的文件夹
3) 不同组之间不可访问各自的文件夹
4) 每个学生在所在组的文件夹下拥有一个所属的文件夹
5) 同组不同学生之间可以查看各自文件夹的内容,但不可以修改,学生只能修改自己的文件内容
6) 请设计测试用例,查看所设计的权限模型是否满足要求。
分组 | 学生 |
designing | zhao qian |
coding | sun li |
testing | zhou wu |
图1 LinuxCourse
图2-10 权限管理创建
su zhao
ls /LinuxDemo/designing # 应该可访问
ls /LinuxDemo/coding # 应该被拒绝
touch /LinuxDemo/designing/qian/test # 应该被拒绝
图2-11 权限管理验证成功
6.进程管理
开启多个终端程序,使用ps命令是查看进程状态,并用kill命令结束其中一个终端程序。
(三个终端在进行kill命令之后只剩下两个终端)
图2-12 终端4138被终止
7.文件压缩和解压
利用gzip命令对某个文件或文件夹进行压缩,然后再对其解压。使用unzip命令对Windows下生成的zip格式的压缩文件进行解压缩。
图2-13 file文件压缩再解压
图2-14 folder文件夹压缩再解压
sudo apt-get install unzip -y --allow-unauthenticated
安装完unzip
rc@rc-desktop:~$ unzip archive.zip
Archive: archive.zip
replace file1? [y]es, [n]o, [A]ll, [N]one, [r]ename: y
inflating: file1
实验三 vi编辑器的使用
一、实验目的
1.学习使用vi编辑器建立、编辑、显示及加工处理文本文件。
二、实验内容
1.进入和退出vi编辑器。
2.利用文本插入方式建立一个文件。
3.在新建的文本文件上移动光标位置。
4.对该文件执行删除、复原、修改、替换等操作。
三、主要实验步骤
1.进入vi编辑器。
2.建立一个文件,如file.c。进入插入方式,输入一个C语言程序的各行内容,故意少写几个字符和几行内容。最后,将该文件存盘。回到shell状态下。
3.利用a,i,o等命令,将少写的内容填补到文件正确的位置,并且保存退出。
4.运行man date > file10,然后vi file10。使用x,dd等命令删除某些文本行。使用u命令复原此前的情况。使用c、r、s等命令修改文本内容。使用检索命令进行给定模式的检索。
四、拓展实验
1. 检查当前系统中是否存在Vim和Visual Studio Code编辑器?如果没有,请在系统里安装Vim和Visual Studio Code,并比较Vi、Vim和Visual Studio Code三个编辑器的使用差异。
五、实验结果
X删除光标下的字母,dd删除整行,o加行并书写,p是粘贴,a是在行尾附加,hjkl左下上右,U撤销行内命令,u撤销命令,c整行删除并可书写,r是替换光标所指某一字符,s是删除光标所指字符并用占位符$替代等待输入替换的字符(替换字符),例如/DATE搜索DATE项,并按n跳转到下一个匹配项。
实验三主要实验步骤不作图片展示,已按照要求做完。
拓展试验:
sudo apt-get update 更新软件源缓存
sudo apt-get install vim 安装vim
vim –version 验证安装
在Ubunto10.04版本上难以下载VS Code,已安装Vim。
图3-2 多角度三者区别
VS Code更多是图形化界面带来的好处,就跟以前的DOS到后来的Windows质的飞跃一样,Vi/Vim学习成本要求很高,就算Vim增强了Vi的功能对于我小白来说,也是不友好的。VS Code美观,也适合大型项目开发。但是vim和vi有其不可替代性,例如终端环境下的唯一选择,具有轻量性与高效性,键盘驱动效率高于鼠标,系统兼容性好(比如10.04就很难安装VSCode)
图3-3 应用场景与缘由
图3-4 vi/vim键位图
实验四 shell编程
一、实验目的
1.了解shell的作用和主要分类。
2.掌握bash的建立和执行方式。
3.掌握bash的基本语法。
4.学会编写shell脚本。
二、实验内容
1.shell脚本的建立和执行。
2.shell变量和位置参数、环境变量。
3.bash的特殊字符。
4.一般控制结构。
5.算术运算及bash函数。
三、主要实验步骤
1.利用vi建立一个脚本文件,其中包括date、cal、pwd、ls等常用命令。然后以不同方式执行该脚本。
2.运行history命令。
3.体会bash的命令补全功能。
4.对教材例题4.9 (P108)进行编辑,然后执行。
5.对教材例题4.19 (P132)进行编辑,然后执行。
6.对习题4.8 (P141)进行编辑,然后执行。
7.对习题4.9进行设计,然后调试、执行。
8.对习题4.11进行设计,然后调试、执行。
9.对习题4.13进行设计,然后调试、执行。
10.对习题4.14进行设计,然后调试、执行。
四、拓展实验
1. Shell编程实现指定输入的加法,比如输入100,计算1+2+3+…+100的和。
2. Shell编程判断指定文件夹下文件的数量。
3. Shell编程判断给定年份是否为闰年。
4. Shell编程实现9×9乘法表。
5. Shell编程实现批量修改文件扩展名,比如将.txt文件修改为.doc文件。
五、实验结果
1. 利用vi建立一个脚本文件,其中包括date、cal、pwd、ls等常用命令。然后以不同方式执行该脚本。
图4-1 步骤一
2.运行history命令。
图4-2 history命令
3.tab补全
(1)基本补全:(已测试)
输入命令前几个字母(如 his),按一次 Tab 自动补全为 history
若存在多个匹配项(如输入 ls 后按两次 Tab),会列出所有可能的补全选项( lsb_release、lsblk )
(2)路径和文件名补全:(已测试)
输入部分路径(如 cd /e 后按 Tab),自动补全为 /etc/
输入 ls /u 后按 Tab,补全为 /usr/
4.例题4.9
图4-2 例题4.9
5.例题4.19,见图4-3.
6.习题4.8
图4-3习题4.8
在做习题4.8的时候遇到了报错:
Line 3: [: 3-1: integer expression expected 2025
多番尝试后报错原因是expr语法“+”“-”符号前后要有空格
图4-4 例题4.19
7.习题4.9
首先创建3个目录,并且将三个目录地下分别创建各自的文件,然后执行命令。
/home/rc/file3' ->`/home/rc/file2/file3' # 复制目录
/home/rc/file3/file3' ->`/home/rc/file2/file3/file3' # 复制内部文件
Copied /home/rc/file3 to /home/rc/file2 # 完成提示
图4-5 习题4.9代码
结果:
代码:(见下页)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | #!/bin/bash if [ "$#" -lt 2 ]; then echo "Usage: $0 <destination_directory> <file_or_dir1> [file_or_dir2] ..." exit 1 fi DEST_DIR="$1" if [ ! -d "$DEST_DIR" ]; then echo "Error: Destination directory '$DEST_DIR' does not exist." exit 1 fi shift # 移除目标目录参数 for ITEM in "$@"; do if [ -e "$ITEM" ]; then cp -rv "$ITEM" "$DEST_DIR" # -r 允许复制目录 echo "Copied $ITEM to $DEST_DIR" else echo "Error: '$ITEM' does not exist." fi done |
File4目录里面的文件file4,File3目录里面的file3文件都放入到目录file2当中。实现结果。
8.习题4.11
代码:
1 2 3 4 5 6 | #!/bin/bash dir="$1" shift for file in "$@"; do cat "$dir/$file" # file 应为目标目录下的文件名 done |
结果:
rc@rc-desktop:~$ ./ex3 /home/rc/file2 file2 file3 file4
22
33
44
9.习题4.13
代码:
1 2 3 | #!/bin/bash cities=(北京 上海 广州 深圳 南京 苏州) for city in "${cities[@]}"; do echo "$city"; done |
结果:
10.习题14
代码:
1 2 3 4 5 6 7 | a=1 b=1 sum=2; for _ in {3..10}; do c=$((a+b)); sum=$((sum+c)); a=$b; b=$c; done; echo $sum |
结果:
11.拓展1 Shell编程实现指定输入的加法,比如输入100,计算1+2+3+…+100的和。
代码:
1 2 3 4 5 6 | #!/bin/bash n=$1; sum=0; for i in $(seq 1 $n); do ((sum+=i)); done; echo $sum |
结果:
12.Shell编程判断指定文件夹下文件的数量
代码:
1 2 | #!/bin/bash echo $(find "${1:-.}" -maxdepth 1 -type f | wc -l) |
结果:
13.shell编程判断给定年份是否是闰年。
代码:
1 2 | #!/bin/bash (($1%4==0&&$1%100!=0||$1%400==0))&&echo Leapyear||echo NoLeapyear |
结果:
14. 用shell编程实现9*9乘法表
代码:
1 2 3 4 5 6 7 | #!/bin/bash for i in {1..9}; do for j in $(seq 1 $i); do echo -ne "$j×$i=$((i*j))\t"; done; echo; done |
输出结果:
15.shell 编程将当前目录下所有.txt文件扩展名批量修改为.doc
代码:
1 2 | #!/bin/bash for f in *.txt; do mv -- "$f" "${f%.txt}.doc"; done |
结果:
实验五 常用开发工具
一、实验目的
1.掌握C语言编译的基本用法。
2.掌握gdb调试工具的基本用法。
3.理解make工具的功能,学会编制makefile的方法。
二、实验内容
1.利用gcc编译C语言程序,使用不同的选项,观察并分析显示结果。
2.用gdb调试一个编译后的C语言程序。
3.编写一个由多个文件构成的C语言程序,编制makefile,运行make工具进行维护。
三、主要实验步骤
1.按照教学视频“Gcc编程和Gdb调试范例”和“静态链接库和动态链接库的创建和调用”,掌握视频中的内容,熟悉下列选项在编译过程中的作用:-c,-o,-l,-L。
2.按照教学视频“程序维护工具make的使用”,重写做一遍,要掌握依赖关系图的画法、makefile文件的编写、及make工具的使用。
3.完成对习题6.9的编制,并使用make进行维护(参考教学视频,自己制作动态链接库文件libm.so)。
四、实验结果
1.步骤一
(1)编写源代码
1 2 3 4 5 6 | #include<stdio.h> int main() { puts("Haha,I am RC"); return 0; } |
(2)代码编译完整过程
预处理->编译->汇编->链接
(3)编译源代码:
gcc -o output example.c
-o用于指定生成的可执行文件的名称,output是输出文件的名称,example.c是源代码文件的名称。
也可以写做:gcc example.c -o output
(4)gcc常用选项
-c:只编译源代码,生成目标文件(xx.o)而不进行链接。
-E:只进行预处理,生成预处理后的源代码文件。
-O:优化生成的代码,可以使用-O1、-O2或-O3进行不同级别的优化
-g:生成调试信息,以便进行源代码级调试。
-Wall:显示编译时的警告信息。
-std:指定所使用的C语言标准,如-std=c11。
-I:指定包含头文件的目录。
-L:指定链接库文件的目录。
-l:链接指定的库文件。
(5)使用GDB调试
1)参数:
-g:在可执行文件中包含调试信息,以便GDB能够进行源代码级别的调试。
-tui:以文本用户界面(TUI)模式启动GDB,该模式提供了源代码窗口和调试器命令窗口。
-b:指定调试器使用的调试文件格式,如ELF、COFF等。
-ex:在启动GDB后立即执行指定的命令。
-core <core文件>:指定要调试的核心转储文件。
-x <脚本文件>:从指定的文件中读取GDB命令,可以用于自动执行一系列的调试命令。
-args <可执行文件> <参数>:指定要调试的可执行文件及其命令行参数。
-p <进程ID>:连接到指定的正在运行的进程进行调试。
2)编译源代码:
1 | gcc -g -o exp example.c |
3)启动gdb:
1 | gdb exp |
4)设置断点break 运行程序run
*在程序执行过程中,可以使用以下常用命令来调试程序:
run:从头运行程序(简写r)。
break:继续设置断点(简写b)。
next:执行下一行代码(简写n)。
step:进入函数调用,逐行执行函数内部的代码(简写s)。
print variable:打印变量variable的值(简写p)。
watch variable: 监视变量variable的值,当变量的值发生改变时,停止程序的执行(简写w)。
continue:继续执行程序直到下一个断点或程序结束(简写c)。
backtrace:显示当前函数调用的堆栈跟踪信息(简写bt)。
quit:退出GDB调试器(简写q)。
finish: 执行到当前函数返回为止(简写fin)。
2.主要实验步骤二
(1)撰写4个.c文件 1个.h文件 一个makefile文件
(2)创建共享库
(3)最后make编译
*依赖关系图的理解:
假设当前工程目录为prj/,该目录下有6个文件,分别是:main.c、abc.c、xyz.c、abc.h、xyz.h和Makefile。其中main.c包含头文件abc.h和xyz.h,abc.c包含头文件abc.h,xyz.c包含头文件xyz.h,而abc.h又包含了xyz.h。
- 主要步骤三
defs.h(公共头文件)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #ifndef DEFS_H #define DEFS_H // 公共函数声明 void common_function(); int calculate_value(int base); #endif a.c(主程序) #include <stdio.h> #include "defs.h" // 声明汇编函数 extern int assembly_add(int a, int b); int main() { common_function();
// 调用汇编函数 int sum = assembly_add(10, 20); printf("Assembly result: %d\n", sum);
// 调用数学库函数 double root = sqrt(25.0); printf("Custom sqrt(25) = %.2f\n", root);
return 0; } |
b.c(模块B)
1 2 3 4 5 6 7 8 | #include <stdio.h> #include "defs.h"
void common_function() { printf("Module B: Common function called\n"); int val = calculate_value(5); printf("Calculated value: %d\n", val); } |
c.c(模块C)
1 2 3 4 5 | #include <stdio.h>
void module_c_function() { printf("Module C: Additional functionality\n"); } |
d.c(模块D)
1 2 3 4 5 6 | #include <stdio.h> #include "defs.h" int calculate_value(int base) { return base * 2 + 10; } |
math.c(数学库实现)
01 02 03 04 05 06 07 08 09 10 11 12 13 | #include <math.h>
// 修改循环变量声明方式 double sqrt(double x) { int i; // 将变量声明移到循环外 if(x < 0.0) return NAN;
double guess = x / 2.0; for(i = 0; i < 20; i++) { // 移除循环内的变量声明 guess = 0.5 * (guess + x / guess); } return guess; } |
assmb.s(汇编模块)
01 02 03 04 05 06 07 08 09 10 11 12 13 | .section .text .global assembly_add
assembly_add: push %ebp mov %esp, %ebp
mov 8(%ebp), %eax add 12(%ebp), %eax
mov %ebp, %esp pop %ebp ret |
编译和运行:
make # 编译项目
./prog # 运行程序
make clean # 清理构建文件
结果:
Makefile(见下页)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # 编译配置 CC = gcc AS = as CFLAGS = -Wall -I. LDFLAGS = -L./lib -lm -Wl,-rpath='$$ORIGIN/lib'
# 文件设置 C_SRCS = a.c b.c c.c d.c ASM_SRC = assmb.s OBJS = $(C_SRCS:.c=.o) $(ASM_SRC:.s=.o) TARGET = prog LIB_DIR = lib LIB_NAME = libm.so
.PHONY: all clean
all: $(LIB_DIR)/$(LIB_NAME) $(TARGET)
$(TARGET): $(OBJS) $(CC) $^ -o $@ $(LDFLAGS)
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
%.o: %.s $(AS) $< -o $@
# 修改后的动态库规则 $(LIB_DIR)/$(LIB_NAME): math.c @mkdir -p $(LIB_DIR) $(CC) -std=c99 -shared -fPIC $< -o $@
b.o d.o: defs.h
clean: rm -f $(OBJS) $(TARGET) rm -rf $(LIB_DIR) |