目录
目录
一、要求
- 编写myod.c,用 myod XXX 实现 Linux 下 od -tx -tc XXX 的功能。
- 复习 c 文件处理内容。
- main 与其他分开,制作静态库和动态库。
- 编写 makefile。
- 提交测试代码和运行结果截图,要全屏,包含自己的学号信息。
- 提交博客,重点写遇到的问题和解决过程。
二、设计流程
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
- 每两行要求显示目标文件的16个字符的对应信息:
- 第一行以每四个字节为一组,依次输出四次,并按照小端法形式输出显示;
- 第二行按序输出这16个字符,每一个十六进制4字节数组的最后一位,对应下第二行四字符一组的最后一位;
- 每要输出一组16字符信息,在开头输出该16字符第一个字符所占的字节序号,文件输出结束时显示最后一字符的字节序列;
- 当文件输出到最后几个字节,不满足16个字符一组时,按照16字符组标准输出,其中若4个4字符组中的一个组没有字符,则不显示。
- 通过命令行参数,调用文件相关命令,实现读取文件。
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,并制作动、静态库
MakefileMakefile
# 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
五、测试及结果
- 读取显示 无数据 文本:
./myod byte_txt/byte_0.txt
- 读取显示 11 比特文本:
./myod byte_txt/byte_11.txt
- 读取显示 16 比特文本:
./myod byte_txt/byte_16.txt
- 读取显示 更多数据 文本:
./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