Linux实验四:编译和调试工具的使用

文章目录

  • 一、实验目的:
  • 二、实验要求
  • 三、实验内容
  • 四、实验操作
    • 1、用gcc编译程序,写出编译过程,并给出运行结果。
    • 2、调试程序,要求用gdb进行调试并给出修改方案。
    • 3、make的使用


一、实验目的:

1、练习并掌握Linux提供的vi编辑器来编译C程序

2、学会利用gcc、gdb编译、调试C程序

3、学会使用make工具


二、实验要求

1、编写C语言程序,用gcc编译并观察编译后的结果,运行生成的可执行文件。

2、利用gdb调试程序。

3、学习编写makefile,并进行编译。


三、实验内容

1、GNU C编译器

(1)使用gcc

通常后跟一些选项和文件名来使用gcc编译器。gcc命令的基本用法如下:
gcc [options] [filenames] 命令行选项指定的编译过程中的具体操作

(2)gcc常用选项

当不用任何选项编译一个程序时,gcc将建立(假定编译成功)一个名为a.out的可执行文件。 选项含义:
-o FILE 指定输出文件名,在编译为目标代码时,这一选项不是必须的。如果FILE 没有指定,默认文件名是a.out. 也可用-o选项来为即将产生的可执行文件指定一个文件名来代替a.out。
-c GCC 仅把源代码编译为目标代码。默认时GCC 建立的目标代码文件有一个.o 的 扩展名。
-E 对文件进行预处理
-S 对文件进行编译,生成汇编代码。
-O 对源代码进行基本优化。这些优化在大多数情况下都会使程序执行得更快。
-g 在可执行程序中包含标准调试信息。
-Wall 允许发出GCC 能提供的所有有用的警告,也可以用-W(warning)来标识指定的警告。
-l name 链接静态库
-L dir 库文件的搜索路径

(3)执行文件

格式: ./可执行文件名

2、gdb调试工具

(1)调试编译代码

为了使gdb正常工作,必须使你的程序在编译时包含调试信息。调试信息里包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb利用这些信息使源代码和机器码相关联。
在编译时用 –g 选项打开调试选项。

(2)gdb基本命令

命令描述
file装入欲调试的可执行文件
kill终止正在调试的程序
list列出产生执行文件的源代码部分
next执行一行源代码但不进入函数内部
step执行一行源代码并进入函数内部
run执行当前被调试的程序
quit终止gdb
watch监视一个变量的值而不管它何时被改变
break在代码里设置断点,使程序执行到这里时被挂起
make不退出gdb就可以重新产生可执行文件
shell不离开gdb就执行UNIX shell 命令

四、实验操作

1、用gcc编译程序,写出编译过程,并给出运行结果。

mypow.c:定义mypow()函数

unsigned long long mypow(unsigned int x, unsigned int y)
{unsigned long long res=1;if (y==0)res = 1;else if (y==1):res = x;elseres = x * mypow(x, y-1);return res;
}

powtest.c:调用mypow()函数

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{unsigned int x, y;unsigned long long res;if ((argc<3) || (sscanf(argv[1], "%u", &x)) != 1 || (sscanf(argv[2], "%u", &y)) != 1 ){printf("Usage:pow base exponent\n");exit(1);}res = mypow(x, y);printf("%u ^ %u = %u\n", x, y, res);return 0;
}

gcc -o命令编译

在这里插入图片描述

gcc命令编译

在这里插入图片描述
在这里插入图片描述

要注意实验中给出的powtest.c文件里没有对mypow.c头文件进行引用,因此做实验的时候自己要加这个头文件如下图第四行

在这里插入图片描述

2、调试程序,要求用gdb进行调试并给出修改方案。

(1)源程序的功能:按照正序和逆序输出给定的字符串。要求用gdb进行调试,分析出错的原因并给出修改方案。

#include <stdio.h>
#include <string.h>
#include <malloc.h>
void my_print (char *string);
void my_print2 (char *string);
int main()
{char my_string[] = "hello there";my_print (my_string);my_print2 (my_string);return 0;
}                                                                                        
void my_print (char *string)
{printf ("The string is %s\n", string);
}                                                                                        
void my_print2 (char *string)
{char *string2;int size, i;size = strlen (string);string2 = (char *) malloc (size + 1);for (i = 0; i < size; i++)string2[size - i] = string[i];string2[size + 2] = '\0';printf ("The string printed backward is %s\n", string2);
}

在这里插入图片描述
在这里插入图片描述
第一种调试方法:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

上述调试方法中从26行跳出,然后查证string数组的值,会发现string[0]位置上的值未被替换,仍为正序输入

第二种调试方法
在这里插入图片描述

上述方法中可以看出来size的值是11,之后的语句size-i我们可知是从string2[11]开始赋值的,那这样我们赋值到string2[1]时,“hello there"就复制结束了,但是string2[0]仍未被赋值,这就出现了错误。

Warning:string2[0]='\000' string2[1]='e' string2[2]='r' string2[size]='h'
也就是说没有从string2[10]开始存储值,而是从string2[11]开始存储的,故string2[0]产生空置。
方案:赋值时应该size-1-i开始逆序赋值,而不是size-i
将 string2[size - i] = string[i]; 替换成 string2[size - i - 1] = string[i];
将string2[size + 2] = ‘\0’; 替换成 string2[size] = ‘\0’;

在这里插入图片描述


3、make的使用

(1)用vi编辑以下程序,程序清单:

main.c

function1.h

function1.c

function2.h

function2.c

//main.c
#include "function1.h"
#include "function2.h" 
int main(int argc, char **argv)
{
function1_print("hello");
function2_print("world");return 0;
}
//function1.h 
void function1_print(char *str); 
//function1.c 
#include "function1.h"
void function1_print(char *str)
{
printf("This is function1 print %s\n", str);
}
//function2.h
void function2_print(char *str); 
//function2.c 
#include "function2.h"
void function2_print(char *str)
{
printf("This is function2 print %s\n", str);
}

(2)实验要求:

a)画出各个源程序、目标文件以及最终的目标文件之间的依赖关系图。

在这里插入图片描述

b)编辑makefile文件

在这里插入图片描述
ps:上传图片的时候才发现自己把function2.o写成function2.0了,我个铁憨憨

c)利用make命令进行上述程序的编译,生成可执行代码并运行。

在这里插入图片描述

d)修改其中一个源文件,重新make,察看编译过程。

在这里插入图片描述

e)通过使用makefile变量和隐含规则,对makefile文件进行简化

在这里插入图片描述

这里的 $(CFLAGS)可以不写,其是c编译器的选项,无默认值,这里我们也不需要选择编译器,但是养成良好的代码习惯也是很必要滴 ~ 万一以后需要选择编译器但没写(不大可能),找起bug来会非常头疼滴 ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux实验五:Linux环境下的C语言编程

文章目录一、实验目的&#xff1a;二、实验要求三、实验内容1、编写一段C语言程序使其完成&#xff1a;父进程创建两个子进程&#xff0c;每个进程都在屏幕上显示自己的进程ID号。2、上机调试下面的程序&#xff0c;观察运行结果&#xff0c;分析原因。3、利用两个管道进行双向…

ndarray对象的建立

文章目录ndarray&#xff08;别名array&#xff09;常用属性创建NumPy数组使用array()函数使用zeros()函数使用ones()函数使用empty()函数使用arange()函数注意ndarray&#xff08;别名array&#xff09; 常用属性 import numpy as np # Numpy工具包data np.arange(12).res…

Numpy数组的广播机制

文章目录前言数组广播广播机制的使用条件前言 Numpy数组不需要循环遍历&#xff0c;即可对每个元素执行批量的算术运算操作&#xff08;矢量化运算&#xff09;。当两个数组大小&#xff08;Numpy.shape&#xff09;不同时&#xff0c;进行算术运算会出现广播机制。 数组广播…

数组的转置和轴对称

文章目录T属性transpose()方法swapaxes()方法T属性 import numpy as np # Numpy工具包data np.arange(12).reshape(3, 4) # 创建一个3行4列的数组 print(data)# 数组的转置和轴对称 data1 data.T print(data1)print(data) [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] print(dat…

管道实现父子进程的信息传递(一)【fork函数、pipe函数、write/read操作、wait函数】

文章目录题目描述代码实现关于pipe函数关于读写操作关于读写端口关于wait函数功能&#xff1a;注意&#xff1a;关于fork函数题目描述 编写一个程序&#xff0c;利用管道实现父子进程的通信&#xff0c;父进程向子进程发送信息&#xff0c;由子进程输出显示。 代码实现 #inclu…

基础的shell编程问题(一)

文章目录题目一题目描述代码实现关于$#的有关内容实测本程序的作用题目二题目描述代码实现注释关于argc、argv关于read函数关于文件描述符关于write函数本程序的作用题目三题目描述代码实现实测关于grep命令关于read命令题目四题目描述代码实现关于test命令实测题目一 题目描述…

基础的shell编程问题(二)

文章目录题目一题目描述代码实现结果验证关于本题题目二题目描述代码实现结果测试题目三题目描述代码实现及结果测试题目四题目描述代码实现及结果测试题目五题目描述代码实现及结果测试题目一 题目描述 输入的命令行参数必须是hello&#xff0c;才会正确显示&#xff1b;否则…

Numpy实现酒鬼漫步问题【以及randint()、where()、cumsum()、argmax()的用法详解】

文章目录题目描述代码实现关于本题涉及到的几个函数randint()where()cumsum()题目拓展题目描述代码实现题目拓展题目描述代码实现argmax()题目描述 从前有一个酒鬼&#xff0c;喝醉了行走在一条直线上&#xff0c;每走一步方向是不确定的&#xff08;向前或者向后&#xff09;…

搞清axis的含义,这一篇就够了!

文章目录axis的含义旁门左道式理解二维数组中的axis三维数组中的axis正规理解axis的含义 在自己分析之前先摆上官方关于多维数组中axis的值的定义&#xff1a; axis 0&#xff0c;表示第一个维度 axis 1&#xff0c;表示第二个维度 axis -1&#xff0c;表示最后一个维度…

Struts2.3.5+Hibernate3+Spring3.1基于注解实现的多文件上传,下载

Struts2.3.5Hibernate3Spring3.1基于注解实现的的多文件上传&#xff0c;下载,这里是上传文件到数据库中&#xff0c;上传控件可以增加和删除&#xff0c;有需要的朋友可以看看。 以下是源码下载地址&#xff1a;http://www.zuidaima.com/share/1639672872438784.htm jar包的下…

【精品计划1】动态规划入门到熟悉,看不懂来打我啊

持续更新。。。。。。 2.1斐波那契系列问题 2.2矩阵系列问题 2.3跳跃系列问题 3.1 01背包 3.2 完全背包 3.3多重背包 3.4 一些变形选讲 2.1斐波那契系列问题 在数学上&#xff0c;斐波纳契数列以如下被以递归的方法定义&#xff1a;F(0)0&#xff0c;F(1)1, F(n)F(n-1)…

【大总结2】大学两年,写了这篇几十万字的干货总结

本文是我大学两年知识的总结。涵盖数据结构、算法、语言基础、操作系统、关系数据库、NOSQL、网络/前端/项目基础知识、安全和测试、框架的学习、中间件和工具、设计模式和框架原理、我推荐的资料、我的建议 本篇文章应该算是Java后端开发技术栈的&#xff0c;但是大部分是基础…

《这是全网最硬核redis总结,谁赞成,谁反对?》六万字大合集

我摊牌了&#xff0c;这篇文章&#xff0c;值得99%的人收藏 此文后续会改为粉丝可见&#xff0c;所以喜欢的请提前关注和收藏&#xff0c;不迷路。 最近有五本我喜欢的redis实体新书&#xff0c;想要的去评论&#xff0c;我写个随机数抽奖包邮送给你。 那么&#xff0c;准备好…

Python数据预处理之异常值的处理——【自定义的three_sigma()函数、boxplot()方法】

文章目录基于3σ原则检测异常值代码实现测试基于箱型图检测异常值异常值的处理基于3σ原则检测异常值 3σ原则&#xff0c;又称拉依达准则。是指假设一组检测数据只含有随机误差。对其进行计算处理得到标准偏差&#xff0c;按一定概率确定一个区间&#xff0c;凡是超过这个区间…

那个谷歌的网红扔鸡蛋的题,来看看教科书式的回答

leetcode顶级难题&#xff0c;谷歌面试天天问&#xff0c;来看看吧&#xff0c;带你来一步一步达到最优解。 谷歌不知道问了多少遍&#xff0c;蓝桥杯也出现过&#xff0c;leetcode上是顶级难题&#xff0c;到底是什么题能如此频繁地出现&#xff1f;我们一探究竟吧。 原题描述…

不骗你,没读这一篇,你不可能懂二分

上篇文章讲动态规划获得了80k浏览&#xff0c;这次的二分也值得你们一看&#xff0c;这个系列是特别用心写的&#xff0c;准备出书的哦 动态规划 3.0 引子 图书馆自习的时候,一女生背着一堆书进阅览室,结果警报响了,大妈让女生看是哪本书把警报弄响了&#xff0c;女生把书倒出…

超硬核!操作系统学霸笔记,考试复习面试全靠它

之后会发布基于基础知识的大部分算法的模拟代码合集&#xff0c;敬请关注。 进程基础 进程的基本概念 程序顺序执行的特征&#xff1a; 1&#xff09;顺序性&#xff1a;处理机严格按照程序所规定的顺序执行&#xff0c;每一步操作必须在下一步操作开始前执行 2&#xff09;封…

超硬核!学霸把操作系统经典算法给敲完了!要知行合一

上期的笔记&#xff0c;浏览快1万了&#xff0c;既然关注的人很多&#xff0c;那就发出来承诺过的算法全模拟&#xff0c;希望帮到你们。 上期的操作系统学霸笔记&#xff0c;考试复习面试全靠它 一、模拟进程调度 功能 data.h #ifndef _Data_h_ #define _Data_h_#include …

超硬核!数据结构学霸笔记,考试面试吹牛就靠它

上次发操作系统笔记&#xff0c;很快浏览上万&#xff0c;这次数据结构比上次硬核的多哦&#xff0c;同样的会发超硬核代码&#xff0c;关注吧。 超硬核&#xff01;操作系统学霸笔记&#xff0c;考试复习面试全靠它 第一次笔记&#xff08;复习c&#xff0c;课程概述&#xff…

超硬核!小白读了这篇文章,就能在算法圈混了

作为一只超级硬核的兔子&#xff0c;从来不给你说废话&#xff0c;只有最有用的干货&#xff01;这些神级算法送给你 目录 第一节 1.1bogo排序 1.2位运算 1.3打擂台 1.4morris遍历 第二节 2.1睡眠排序 2.2会死的兔子 2.3矩阵快速幂 2.4摔手机/摔鸡蛋 时空复杂度目录 …