• 2019-2020-1 《信息安全系统设计基础》MyOD




    一、要求

    1. 编写myod.c,用 myod XXX 实现 Linux 下 od -tx -tc XXX 的功能。
    2. 复习 c 文件处理内容。
    3. main 与其他分开,制作静态库和动态库。
    4. 编写 makefile。
    5. 提交测试代码和运行结果截图,要全屏,包含自己的学号信息。
    6. 提交博客,重点写遇到的问题和解决过程。


    二、设计流程

    1. 需求分析

    执行 od -tx -tc 1.txt 的命令显示如下:

    [yogile@yogile-pc MyOD]$ od -tx -tc 1.txt 
    0000000        0a333231        0a333231        34340a0a        0a343434
              1   2   3  
       1   2   3  
      
      
       4   4   4   4   4  
    
    0000020        32330a0a        34323334        32330a32        34323334
             
      
       3   2   4   3   2   4   2  
       3   2   4   3   2   4
    0000040        0000000a
             
    
    0000041
    
    1. 每两行要求显示目标文件的16个字符的对应信息:
    2. 第一行以每四个字节为一组,依次输出四次,并按照小端法形式输出显示;
    3. 第二行按序输出这16个字符,每一个十六进制4字节数组的最后一位,对应下第二行四字符一组的最后一位;
    4. 每要输出一组16字符信息,在开头输出该16字符第一个字符所占的字节序号,文件输出结束时显示最后一字符的字节序列;
    5. 当文件输出到最后几个字节,不满足16个字符一组时,按照16字符组标准输出,其中若4个4字符组中的一个组没有字符,则不显示。
    6. 通过命令行参数,调用文件相关命令,实现读取文件。

    2. 概要设计

    • (1) main.c 实现文件读取操作,通过循环输出每16字符第一个字符所占的字节序号,积极在循环中调用输出显示函数,最后显示最后一字符的字节序号。

    • (2) tans_0x.c 实现函数 void tans_0x(char char_pl[], int i); 实现对每16字符组输出显示,以每四个字节为一组,依次输出四次,并按照小端法形式输出显示。

    • (3) tans_pr.c 实现函数 void tans_pr(char char_pl[], int i); 按序输出该16字符组,与 tans_0x(); 函数输出对齐。

    伪代码

    // 头文件
    int main(/* 命令行参数 */) {
        if (/* 打开文件失败条件*/) {
            // 结束程序
        }
        while(/* 条件 */) {
            // 调用tans_0x();
            // 调用tans_pr();
        }
        if (/* 判断文件有字符 */) {
            // 输出最后一字符的字节序号
        }
        else {
            // 输出 "0000000"
        }
        return 0;
    }
    
    void tans_0x(char char_pl[], int i_n) {
        // for循环,将16字符组以每四个字节为一组,按照小端法形式排序
        if (/* 4字符组为"00000000"时 */) {
            // 不输出
        }
        else {
            // 输出
        }
    }
    
    void tans_0x(char char_pl[], int i_n) {
        for (/* i从0到i_n-1*/) {
            if (char_pl[i] == '
    ') {
                printf("  \n");
            }
            else {
                // 输出字符
            }
        }
    }
    

    3. 详细设计

    main.c

    main.c
      
    # include 
    # include 
    # include "tansp.h"
    

    int main(int argc, char *argv[])
    {
    // 调用命令行参数args[0],实现文件的选择
    FILE *fp=NULL;

    if ( (fp = fopen(argv[1], "r")) == NULL) {
        printf("您输入的文件有误,请重新输入。
    ");
        exit(0);
    }
    char ch;
    char char_perline[16];
    int i=0,j=0,k=0;
    int flag_change=0;
    
    while( (ch = fgetc(fp)) != EOF )
    {
        if (i % 16 == 0) {
            printf("%07o",16*j);
            j++;
        }
        if (i == 16) {
            i=0;
            for (k=0; k<16; k++) {
                char_perline[k] = '';
            }
        }
        
        if (i < 16) {
            char_perline[i] = ch;
            if (i == 15) {
                tans_0x(char_perline, 16);
                tans_pr(char_perline, 16);
                printf("
    ");
            }
        }
        i++;
        flag_change++;
    }
    if (flag_change != 0) {
        if (i < 16) {
            tans_0x(char_perline, i);
            tans_pr(char_perline, i);
            printf("
    ");
        }
        printf("%07o
    ",16*(j-1)+i);
    }
    else {
        printf("0000000
    ");
    }
    fclose(fp);
    return 0;
    

    }

    tans_0x.c

    tans_0x.c
      
    # include 
    # include 
    # include "tansp.h"
    

    void tans_0x(char char_pl[], int i_n) {
    int i,j;
    int i_t=0;
    int left_n = i_n % 4;
    int have_n = i_n / 4;
    char char_temp[16] = {0};
    for (i=i_n; i<16; i++) {
    char_pl[i] = '';
    }
    for (int i=0; i<4; i++) {
    char_temp[4i+3] = char_pl[4i+0];
    char_temp[4i+2] = char_pl[4i+1];
    char_temp[4i+1] = char_pl[4i+2];
    char_temp[4i+0] = char_pl[4i+3];
    }
    for (i=0; i<8; i++) {
    printf(" ");
    }
    for (i=0; i<4; i++) {
    if (i != 0) {
    printf(" ");
    }
    if (char_temp[4i] == '') {
    if (char_temp[4
    i+1] == '') {
    if (char_temp[4i+2] == '') {
    if (char_temp[4
    i+3] == '') {
    // 不输出
    break;
    }
    }
    }
    }
    for (j=0; j<4; j++) {
    printf("%.2x", char_temp[4*i+j]);
    }
    }
    printf(" ");
    }

    tans_pr.c

    tans_pr.c
      
    # include 
    # include 
    # include "tansp.h"
    

    void tans_pr(char char_pl[], int i_n) {
    int i_t=0;
    printf(" ");
    for (i_t=0; i_t < i_n; i_t++) {
    if (char_pl[i_t] == ' ') {
    printf(" ");
    }
    else if (char_pl[i_t] == '') {
    break;
    }
    else {
    printf(" %c", char_pl[i_t]);
    }
    }
    }

    tansp.h

    tansp.h
      
    #ifndef TANSP_H
    #define TANSP_H
    

    void tans_pr();
    void tans_0x();

    endif



    三、编写Makefile,并制作动、静态库

    Makefile

    Makefile
      
    ```
    # This is a make file.
    

    Generate using static library.

    myod:bin/myod
    ln -s bin/myod myod
    bin/myod:src/main.c libs/libtansp.a
    gcc src/main.c libs/libtansp.a -I include/ -o bin/myod
    libs/libtansp.a:libs/tans_pr.o libs/tans_0x.o
    ar rcvs libs/libtansp.a libs/tans_pr.o libs/tans_0x.o
    libs/tans_pr.o:src/tans_pr.c
    gcc -c src/tans_pr.c -I include/ -o libs/tans_pr.o
    libs/tans_0x.o:src/tans_0x.c
    gcc -c src/tans_0x.c -I include/ -o libs/tans_0x.o

    Generate using dynamic library.

    bin/myod_so:src/main.c libs_so/libtansp.so
    gcc src/main.c libs_so/libtansp.so -I include/ -o bin/myod_so
    libs_so/libtansp.so:libs_so/tans_pr.o libs_so/tans_0x.o
    gcc -shared -o libs_so/libtansp.so libs_so/tans_pr.o libs_so/tans_0x.o
    libs_so/tans_pr.o:src/tans_pr.c
    gcc -fPIC -c -I include/ src/tans_pr.c -o libs_so/tans_pr.o
    libs_so/tans_0x.o:src/tans_0x.c
    gcc -fPIC -c -I include/ src/tans_0x.c -o libs_so/tans_0x.o

    </code></pre>
    </details>
    
    直接使用 `Linux$ make` 默认制作静态库,在5-12行前加 `#` 使用 `Linux$ make` 可制作动态库。
    
     - make 制作静态库:
    ![](https://img2018.cnblogs.com/blog/1591904/201909/1591904-20190928183451316-1742068637.png)
    
     - make 制作动态库:
    ![](https://img2018.cnblogs.com/blog/1591904/201909/1591904-20190928183439725-1395422407.png)
    
    
    <br>
    
    ****
    # 四、创建对于 bin/myod 的链接
    
    `Linux$ ln -s bin/myod myod` 在项目文件夹下创建对于 bin/myod 的链接,可直接 `./myod XXX` 运行。
    输入 `Linux$ ls -l myod` 可看到:
    

    lrwxrwxrwx 1 yogile yogile 8 9月 28 15:32 myod -> bin/myod

    
    <br>
    
    ****
    # 五、测试及结果
    
    1. 读取显示 无数据 文本: `./myod byte_txt/byte_0.txt`
    2. 读取显示 11 比特文本: `./myod byte_txt/byte_11.txt`
    3. 读取显示 16 比特文本: `./myod byte_txt/byte_16.txt`
    4. 读取显示 更多数据 文本: `./myod byte_txt/byte_more.txt`
    
    ![](https://img2018.cnblogs.com/blog/1591904/201909/1591904-20190928183140184-2127763502.png)
    
    
    <br>
    
    ****
    # 六、遇到的问题和解决过程
    
    ## 1. 段错误 (核心已转储)
    
    编译链接生成可执行文件时没有问题,但在运行时报错:
    

    [yogile@yogile-pc MyOD]$ ./myod byte_txt/byte_0.txt
    段错误 (核心已转储)

    
     - 问题原因分析:
    由于在 `main.c` 中的命令行参数输入错误,导致访问不存在的内存地址。
    

    int main(char *argv[]) {
    printf("args[1] = %s",argv[1]);
    ...
    }

    
     - 问题解决方法:
    输入正确的格式:
    

    int main(int argc, char *argv[]) {...

    
    ## 2. 警告:比较指针和整数
    
    为了判定文件的字符是否读完,我想得是没有字符复制给 `char_perline[i]`,其值为空,但报错:
    

    [yogile@yogile-pc M[yogile@yogile-pc src]$ gcc main.c -o main.out
    main.c: 在函数‘main’中:
    main.c:23:35: 警告:比较指针和整数
    23 | for (i=0; char_perline[i] != NULL; i++) {
    | ^~
    main.c:29:35: 警告:比较指针和整数
    29 | for (i=0; char_perline[i] != NULL; i++) {
    |

    
     - 问题原因分析:
    错误是比较了指针和整数。
    实际上,我使用的 while循环的条件是 `(ch = fgetc(fp)) != EOF` 。当文件读完时,循环直接停止,不再赋值给 `char_perline[i]` 。
    
     - 问题解决方法:
    在赋值前,将 `char char_perline[]` 的每一项初始化为 `` ,`` 的16进制编码是 00,`NULL` 改成 `''` 。
    
    ## 3. 警告:隐式声明函数
    
    

    [yogile@yogile-pc MyOD]$ make
    gcc src/main.c libs/libtansp.a -I include/ -o bin/myod
    src/main.c: 在函数‘main’中:
    src/main.c:29:17: 警告:隐式声明函数‘tans_0x’ [-Wimplicit-function-declaration]
    29 | tans_0x(char_perline, 16);
    | ^~~~~~~

    
     - 问题原因分析:
    缺少声明 `tans_0x()` 函数的头文件。
    
     - 问题解决方法:
    添加声明 `tans_0x()` 函数的头文件:`# include "tansp.h"` 。
    
    ## 4. 读取无字符或字符数小于16个的文件,输出乱码。
    
    

    [yogile@yogile-pc MyOD]$ ./myod byte_txt/byte_0.txt
    7dffffffeb6750 0000563f 7dffffffeb60ffffffa0 0000563f

    37777777760

    [yogile@yogile-pc MyOD]$ ./myod byte_txt/byte_11.txt
    000000 34333231 38373635 5f0a6139 00005633
    1 2 3 4 5 6 7 8 9 a
    000013

    
     - 问题原因分析:
    

    int main(/* 命令行参数 /) {
    if (/
    打开文件失败条件/) {
    // 结束程序
    }
    while(/
    条件 */) {
    // 调用tans_0x();
    // 调用tans_pr();
    }
    // 输出最后一字符的字节序号
    return 0;
    }

    其中第 9 行 `// 输出最后一字符的字节序号` ,在实际调用中 `tans_0x(char_perline, 16);` 向函数中传递了16个字节数据,但实际数据字符并没有16个字节。所以输出时输出没赋值的 `char_perline[i]` 时,输出乱码。
     - 问题解决方法:
    添加变量 `flag_change = 0` ,只要while语句运行,就 `flag_change++`。添加 if 语句,进行判断剔除。
    

    if (flag_change != 0) {
    if (i < 16) {
    tans_0x(char_perline, i);
    tans_pr(char_perline, i);
    printf(" ");
    }
    printf("%07o ",16*(j-1)+i);
    }
    else {
    printf("0000000 ");
    }

    
    <br>
    
    ****
    # 七、下载及码云链接
     - [MyOD.zip下载](https://files.cnblogs.com/files/Yogile/MyOD.zip)
     - 码云链接:https://gitee.com/Yogile/Cpt_System_Yogile/tree/master/week_homework
    
    <br>
    
    ****
    # 八、问题解决参考资料
      - [C语言再学习 -- 段错误(核心已转储)](https://blog.csdn.net/qq_29350001/article/details/53780697)
  • 相关阅读:
    vue 开发环境搭建
    签名算法
    MySQL explain执行计划优化
    查看运行时某个java对象占用JVM大小及通过idea查看java的内存占用情况
    jenkins 配置
    CSS布局
    《JavaScript 代码优化指南》
    JavaScript 跨域漫游
    iFrame 功能详解
    粘性的底部布局
  • 原文地址:https://www.cnblogs.com/Yogile/p/11603755.html
Copyright © 2020-2023  润新知