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

青春壹個敷衍的年華 提交于 2019-11-30 16:43:26

目录



一、要求

  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  \n   1   2   3  \n  \n  \n   4   4   4   4   4  \n
0000020        32330a0a        34323334        32330a32        34323334
         \n  \n   3   2   4   3   2   4   2  \n   3   2   4   3   2   4
0000040        0000000a
         \n
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] == '\n') {
            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("您输入的文件有误,请重新输入。\n");
        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

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

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 

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


直接使用 Linux$ make 默认制作静态库,在5-12行前加 # 使用 Linux$ make 可制作动态库。

  • make 制作静态库:

  • make 制作动态库:



四、创建对于 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



五、测试及结果

  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



六、遇到的问题和解决过程

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[] 的每一项初始化为 \0\0 的16进制编码是 00,NULL 改成 '\0'

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  \n
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("\n");
    }
    printf("%07o\n",16*(j-1)+i);
}
else {
    printf("0000000\n");
}



七、下载及码云链接

  • MyOD.zip下载
  • 码云链接:https://gitee.com/Yogile/Cpt_System_Yogile/tree/master/week_homework



八、问题解决参考资料

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!