• 内农大《嵌入式基础》实验二 C语言进阶和Makefile


    一、 实验目的

    1. 利用多文件编程,掌握Linux环境下C程序的编辑、编译、运行等操作。
    2. 掌握Makefile文件的编写、变量及隐式规则和模式规则的应用。
    3. 掌握Linux环境下main函数的参数。
    4. 掌握各类指针的应用。

    二、 实验任务与要求

    1. 根据实验要求编写C语言程序;
    2. 写出各个程序的运行结果并分析; //错误调试 关键代码解释
    3. 根据要求写出Makefile文件;
    4. 利用Makefile文件对多文件程序进行编译。

    三、 实验内容

    1. 开发一个计算器,要求多文件编程,文件之间的调用关系如下图:
      在这里插入图片描述

    (1) 在inputNum.c文件中输入一组数;
    (2) 在Caculator.c文件中在对输入的一组数据进行运算,采用哪些运算请自行设计,但每种运算要单独放在一个自定义函数中,所有运算函数放在Caculator.c文件中;
    (3) 在myDisplay.c文件中输出这一组数的各个运算结果。

    提示:这里Caculator我就整了一个计算函数sumNums,但实际上可以写好多个,比如求一组数的平均数、求一组数中的最大值、最小值啥的…,这里只写了一个仅为演示

    // Caculator.h
    int sumNums(int arr[], int n);
    
    • 1
    • 2
    // Caculator.c
    #include "Caculator.h"
    int sumNums(int arr[], int n) {
        int sum = 0;
        int i; 
        for (i=0;i<n;i++){
            sum += arr[i];
        }
        return sum;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // myDisplay.h
    void display(int a[], int n);
    
    • 1
    • 2
    // myDisplay.c
    #include 
    #include "Caculator.h"
    #include "myDisplay.h"
    
    void display(int a[], int n) {
        printf("求和结果为:%d\n", sumNums(a, n));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // inputNum.h
    void readNums(int arr[], int n);
    
    • 1
    • 2
    // inputNum.c
    #include 
    #include "inputNum.h"
    void readNums(int arr[], int n) {
        printf("请输入 %d 个数,以空格隔开:\n", n);
        int i;
        for (i=0;i<n;i++) {
            scanf("%d", &arr[i]);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // main.c
    #include "inputNum.h"
    #include "myDisplay.h"
    
    int main() {
        int a[5];
        readNums(a, 5);
        display(a, 5);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 将上述编写的多文件进行预处理、编译、汇编、链接几步来完成多文件的编译。注意每一步骤需要编译的文件扩展名。

    2022-11-12 更新:

    # 预处理
    gcc -E main.c -o main.i
    gcc -E myDisplay.c -o myDisplay.i
    gcc -E inputNum.c -o inputNum.i
    gcc -E Caculator.c -o Caculator。i
    
    gcc -S main.c myDisplay.c inputNum.c Caculator.c # 编译
    gcc -c main.c myDisplay.c inputNum.c Caculator.c # 汇编
    gcc -o main main.o myDisplay.o inputNum.o Caculator.o # 链接
    
    ./main
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    在这里插入图片描述

    1. 编写上述多文件程序的Makefile文件。
    main: main.o myDisplay.o inputNum.o Caculator.o
    	gcc -o main main.o myDisplay.o inputNum.o Caculator.o
    main.o: main.c
    	gcc -c main.c 
    inputNum.o: inputNum.c
    	gcc -c inputNum.c
    myDisplay.o: myDisplay.c
    	gcc -c myDisplay.c
    Caculator.o: Caculator.c
    	gcc -c Caculator.c
    
    clean:
    	rm *.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 编写上述程序的Makefile文件,要求在文件中使用自定义变量和预定义变量。
    OBJ = main.o myDisplay.o inputNum.o Caculator.o
    TARGET = main
    $(TARGET): $(OBJ)
    	gcc -o $@ $^
    main.o: main.c
    	gcc -c $<
    inputNum.o: inputNum.c
    	gcc -c $<
    myDisplay.o: myDisplay.c
    	gcc -c $<
    Caculator.o: Caculator.c
    	gcc -c $<
    	
    clean:
    	rm $(OBJ) $(TARGET)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 根据隐式规则和模式规则进行Makefile文件的编写。
    OBJ = main.o myDisplay.o inputNum.o Caculator.o
    TARGET = main
    CFLAGS = -Wall -g
    $(TARGET): $(OBJ)
    	$(CC) $^ -o $@ $(CFLAGS)
    %.o: %.c
    	$(CC) -c $< -o $@ $(CFLAGS)
    clean:
    	rm $(OBJ) $(TARGET)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 利用gdb调试工具对上述程序生成的可执行文件进行调试,在各个自定义函数中设置断点,单步执行并查看断点处变量和数组的值。

    提示:进行调试前需要用 隐式规则和模式规则版本(上面标号为5的)的 makefile 来构建可执行程序。原因是这个版本的makefile 刚好有 -g 选项

    在这里插入图片描述

    构建好之后,运行 gdb main 进入调试

    在这里插入图片描述

    (gdb) list
    (gdb) break 6
    (gdb) break 7
    (gdb) run
    (gdb) print a
    (gdb) next
    (gdb) print a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    1. 请利用main函数的参数编写程序实现计算器的功能。
      如:运行程序及结果如下:
      tarena@ubuntu:~/test/d1$ ./t1 5 + 8
      5 + 8=13.000000
      tarena@ubuntu:~/test/d1$ ./t1 9 / 3
      9 / 3=3.000000
    // t1.c
    #include 
    #include 
    
    int main(int argc, char* argv[]) {
        int a = atoi(argv[1]);
        char oper = argv[2][0];
        int b = atoi(argv[3]);
        double ans = 0;
        if (oper == '+') {
            ans = a + b;
        } else if (oper == '-') {
            ans = a - b;
        } else if (oper == '*') {
            ans = a * b;
        } else if (oper == '/') {
            ans = (double)a/b;
        }
        printf("%d%c%d=%.6lf\n",a,oper,b,ans);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    1. 深入理解数组指针和指针数组的含义,利用数组指针、指针数组以及指向指针的指针分别输出二维数组的值,程序结果如下图所示。
      在这里插入图片描述
    #include 
    
    int main() {
        int arr[4][4] = {
            {0, 1, 2, 3},
            {4, 5, 6, 7},
            {8, 9, 10, 11},
            {12, 13, 14, 15}
        };
    	int i,j;
        printf("使用指针数组的方式访问二维数组arr\n");
        int *pa[4];
        for (i=0;i<4;i++){
            pa[i] = arr[i];
            for (j=0;j<4;j++){
                printf("%d\t", *(pa[i]+j));
            }
            printf("\n");
        }
    
    
        printf("使用数组指针的方式访问二维数组arr\n");
        for (i=0;i<4;i++){
            int (*pb)[4] = arr + i;
            for (j=0;j<4;j++){
                printf("%d\t", *(*pb + j));
            }
            printf("\n");
        }
    
        printf("使用指向指针的指针的方式访问二维数组arr\n");
        for (i=0;i<4;i++){
            int *pc = *(arr + i);
            for (j=0;j<4;j++){
                int *pd = pc + j;
                printf("%d\t", *pd);
            }
            printf("\n");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 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
    • 38
    • 39
    • 40

    在这里插入图片描述

    四、实验总结

    好绕一指针!

  • 相关阅读:
    掌握 Android 自动化测试框架 UiAutomator & UiAutomator2
    mysql迁移以及迁移后配置文件的编写
    基于SpringBoot+Vue的闲一品交易平台设计与实现
    Mysql8 创建表,按年/月或其他条件进行分区存储
    ComfyUI搭建
    JS中的迭代器、可迭代对象、生成器
    为什么很多新型编程语言都抛弃了 C 语言风格的 for 语句?
    reatc的几个基础的hooks
    C语言--输出1-100以内同时能被3和5整除的数
    超声波清洗机有没有平价又好用的推荐、平价好用超声波清洗机总结
  • 原文地址:https://blog.csdn.net/okfang616/article/details/127339986