一、实验目的

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

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

3、学会使用 make 工具

二、实验环境

阿里云服务器,操作系统为CentOS  7.9 64位

三、实验过程

­­­­­­­1. 编写一个简单的 C 语言程序:输出两行文字“How are you”,在 Linux 下编辑、编译、运行。

2. 编写一个简单的 C 语言程序:根据输入的两个整数求平均值并且在终端输出,通过 gcc 编译器得到它的汇编程序文件。

3. Makfile 文件中的每一行是描述文件间依赖关系的 make 规则。

对于下面的 Makefile 文件:

CC = gcc OPTIONS = -O3 -o

OBJECTS = main.o stack.o misc.o

SOURCES = main.c stack.c misc.c

HEADERS = main.h stack.h misc.h

polish: main.c $(OPJECTS)

$(CC) $(OPTIONS) polish $(OBJECTS) -lm

main.o: main.c main.h misc.h

stack.o: stack.c stack.h

misc.h misc.o: misc.c misc.h

回答:

a. 所有变量名字

CC,OPTIONS

b. 所有目标文件的名字

main.o,stack.o,misc.o

c. 每个目标的依赖文件

main.o:main.c,main.h,misc.h

stack.o:stack.c,stack.h,misc.h

d. 生成每个目标文件所需执行的命令

cc -c main.c

cc -c stack.c

cc -c misc.c

e. 画出 makefile 对应的依赖关系树。

f. 生成 main.o,为什么?

 因为需要将编译后的代码变成汇编代码,生成main.o文件和Target有依赖关系,想要编译成功target必须生成main.o文件。

4.用编辑器创建 main.c, compute.c, input.c, compute.h, input.h 和 main.h 文件。下面是 它们的内容。注意 compute.h 和 input.h 文件仅包含了 compute 和 input 函数的声明 但没有定义。定义部分是在 compute.c 和 input.c 文件中。main.c 包含的是两条显示 给用户的提示信息。(相关程序代码如下)

[user@localhost user]$ cat compute.h 

 /*compute 函数的声明原型*/
double compute(double,double);

[user@localhost user]$ cat input.h

/*input 函数的声明原型*/
double input(char*);

[user@localhost user]$ cat main.h

/*声明用户提示*/
#define PROMPT1 "请输入 x 的值:"
#define PROMPT2 "请输入 y 的值:"

[user@localhost user]$ cat compute.c

#include<stdio.h>
#include<math.h>
#include "compute.h"
double compute(double x,double y) {
    return (pow((double)x,(double)y));
}

[user@localhost user]$ cat input.c

#include<stdio.h> 
#include "input.h" 
double input(char *s) {
    float x;
    printf("%s",s);
    scanf("%f",&x);
    return (x);
}

[user@localhost user]$ cat main.c 

#include<stdio.h>
#include "main.h" 
#include "compute.h" 
#include "input.h" 
int main(int argc, char *argv[]) { 
    double x,y; 
    printf("本程序从标准输入获取 x 和 y 的值并显示 x 的 y 次方.\n"); 
    x=input(PROMPT1); 
    y=input(PROMPT2); 
    printf("x 的 y 次方是:%6.3f\n",compute(x,y)); 
    return 0;
}

结合上面代码创建 Makefile 文件,使用 make 命令,生成 power 可执行文件,并运行 power 程序。给出完成上述工作的步骤和程序运行结果。

5. 下面程序的功能是提示你输入一个整数并把它显示到屏幕上,现在它能够通过编译 但运行不正常。利用 gdb 找出它的错误并改正它。重新编译和运行改过的程序以确 保它工作正常。

#include<stdio.h>

#define PROMPT "请输入一个整数:"

void get_input(char *, int *);

void main() {

        int *user_input;

        get_input(PROMPT, user_input);

        (void) printf("你输入了:%d。\n", user_input);

}

void get_input(char *prompt, int *ival){

        (void) printf("%s", prompt);

        scanf("%d", ival);

}

编译成功但是运行出错,系统提示段错误,估计是非法访问内存之类的问题

开始用gdb调试程序

可以看到user_input开始没初始化,把默认的NULL传给了形参 ival ,SEGV应该是Segmentation Violation的意思。

 NULL 的地址是 0x0 ,在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。

调试结束后修改程序代码,为user_input分配空间

这里发现虽然运行没报错,但输出结果是有问题的,很容易想到是print时没给user_input解引用从而把地址给输出来了,如果要继续调试的话的步骤都差不太多,这里直接修改程序代码,运行成功。 

四、实验心得

在Linux上编写 C 语言程序,学会了用gcc 编译并观察编译后的结果,运行生成的可执行文件。学会利用 gdb 调试程序,学会了如何编写 makefile,并进行编译。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐