20191218 2021-2022-diocs-MyOD
一、任务详情
- 复习c文件处理内容
- 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能
- main与其他分开,制作静态库和动态库
- 编写Makefile
- 提交测试代码和运行结果截图, 提交调试过程截图,要全屏,包含自己的学号信息
- 在博客园发表一篇博客,重点写遇到的问题和解决过程
二、实践过程
1. C语言文件操作归纳整理
C语言的文件处理功能设置缓冲区的文件处理方式:
当使用标准I/O函数(包含在头文件stdio.h中)时,系统会自动设置缓冲区,并通过数据流来读写文件。当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,
当写入文件时,并不会马上写入磁盘中,而是先写入缓冲区,只有在缓冲区已满或“关闭文件”时,才会将数据写入磁盘
其余有关内容可参考之前的博客20191218 2021-2022-1-diocs第二周学习笔记
2. Linux下od命令
(1)功能
od命令用于将指定文件内容以八进制、十进制、十六进制、浮点格式或ASCII编码字符方式显示,通常用于显示或查看文件中不能直接显示在终端的字符。
常见的文件为文本文件和二进制文件。od命令主要用来查看保存在二进制文件中的值,按照指定格式解释文件中的数据并输出。
(2)命令格式
od [<选项><参数>] [<文件名>]
(3)命令选项
-t<TYPE>
:指定输出格式,格式包括a、c、d、f、o、u和x,各含义如下:
a:具名字符;
c:ASCII字符或者反斜杠;
d[SIZE]:十进制,正负数都包含,SIZE字节组成一个十进制整数;
f[SIZE]:浮点,SIZE字节组成一个浮点数;
o[SIZE]:八进制,SIZE字节组成一个八进制数;
u[SIZE]:无符号十进制,只包含正数,SIZE字节组成一个无符号十进制整数;
x[SIZE]:十六进制,SIZE字节为单位以十六进制输出,即输出时一列包含SIZE字节。在默认条件下,以四个字节为一组输出
3. myod的实现
本次实践中所涉及代码已上传到码云:第三周代码
od -tx -tc XXX
是先在以十六进制输出XXX文件内容的同时,输出字节对应的ASCII值,它与 od -tx -tc XXX的区别在于输出的次序
OpenEuler下od -tx -tc hello.c的效果
代码实现
我将main函数放在myod.c文件中,剩下需调用的函数放在了myod_func.c文件中,所需的头文件放在myod.h中。
下面是各部分的代码:
myod.c
#include "myod.h"
void main(int argc,char *argv[])
{
char str[BUFFERSIZE];
int num,i,j,i2;
int fd;
if((strcmp(argv[1], "-tx")!=0)|(strcmp(argv[2], "-tc")!=0))
{
printf("输入格式错误");
exit(0);
}
for(num=0; num<strlen(str); num++)
str[num] = '0';
num = 0;
if ((fd = open(argv[3], O_RDONLY)) == -1 )
{
perror(argv[3]);
exit(1);
}
num = read(fd, str, BUFFERSIZE);
close(fd);
int LJ;
int SY;
int tx[8];
char tx2[8];
int tSY,Dan;
for(LJ = 0,SY = num;;)
{
for(j=0; j<8; j++)tx[j] = 0;
Change(LJ,tx,tx2);
for(j=0; j<8; j++)
printf("%c",tx2[j]);
printf(" ");
//累计字符输出完毕
tSY = SY;
if(tSY>=16)
{
Dan = 16;
}
else
{
Dan = tSY;
}
for(j=LJ; j<Dan+LJ; j++)
{
if(str[j]=='
')
{
printf("\n ");
}
else
{
printf("%c ",str[j]);
}
}
printf("
");
//输出文本
outputAscii(tx2,Dan,LJ,tx,str);
if(2==count(&tSY,&Dan,&LJ,&SY,&num))exit(0);
}
}
myod_func.c
#include "myod.h"
void Change(int LJ,int tx[],char tx2[])
{
dToH(LJ,tx);
int i;
for(i=0; i<8; i++)
{
tx2[i] = intToChar(tx[i]);
}
}
void dToH(int H,int tx[])//十进制转十六进制,但此时仍用int存储
{
if(H>536870911)
{
printf("字符数太大,超出限制
");
exit (0);
}
int i=7;
for(; i>0;)
{
tx[i] = H%16;
H = H/16;
i--;
}
}
char intToChar(int t)//十六进制,把int[]转为char[]
{
if((t>=0)&&(t<10))
{
return t+48;
}
else
{
return t+87;
}
}
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num)//计数并判定是否终止
{
*tSY = *tSY-*Dan;
printf("
");
if(*SY>=16)
{
*LJ = *LJ+16;
}
else if((*SY>0)&&(*SY<16))
{
*LJ = *LJ+*SY;
}
else if(*SY==0)
{
return 2;
}
*SY = *num-*LJ;
return 1;
}
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[])
{
int tt,j,i2;
printf(" ");
for(j=LJ; j<Dan+LJ; j++)
{
tt = str[j];
Change(tt,tx,tx2);
for(i2=0; i2<8; i2++)
{
if(tx2[i2]!='0')break;
}
for(;i2<8;i2++)printf("%c",tx2[i2]);
printf(" ");
}
printf("
");
}
myod.h
#ifndef _MYOD_H_TQH_
#define _MYOD_H_TQH_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERSIZE 1000
void Change(int LJ,int tx[],char tx2[]);
void dToH(int H,int tx[]);
char intToChar(int t);
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num);
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[]);
#endif
复习制作静态库和动态库
- 静态库
注意在第一次制作静态库时加上-Iinclude链接头文件,生成.a静态库之后可以不需要再加,直接编译即可。 - 动态库
注意每次都要加-Iinclude。
制作myod静态库和动态库
-
静态库
tree下的结构图
用静态库运行myod结果
可以看到实现了od -tx -tc XXX
的要求 -
动态库
上面这张截图中我忘记添加-o参数指定输出路径,在当前目录下生成了a.out,下图是修改后的。
下图是在动态库下的运行结果
-
问题1:执行的时候不能找到动态库,如下图
可以发现同静态库、直接用od命令结果一致。
Makefile
makefile的存在主要是为了通过提前编写好文件依赖关系的脚本,实现自动化编译运行,提高效率。
-
制作makefile
-
Makefile练习
myt实现的功能是:从键盘读入两整数,使用、输出两整数的和。
尝试使用对myod用makefile
首先是未在所有出现文件前加上相对路径,只在gcc语句中出现的文件加相对路径,出现了如下提示
尝试着都加上相对路径
结果编译报错找不到头文件,一看还是忘了加-Iinclude选项
加上Iinclude选项后还是出错
结果查看树形图发现根本没有myod_func.o,之前在编译生成myod.o时已经是把两个文件一起编译成myod.o目标文件了,并且之前存放.o文件的路径也是在lib下
重新开始,又出现了新的问题
仔细检查发现是gcc编译的几个参数弄混了,-c对应的才是生成目标文件。
成功实现用Makefile完成gcc编译。
解决办法:
- 拷贝到系统的库路径下(不推荐)
- 修改LD_LIBRARY_PATH环境变量,将库所在的路径添加到环境变量中,用冒号分割。
假设libfile.so在/root/LProject_20191218TangQiheng中
export LD_LIBRARY_PATH=//root/LProject_20191218TangQiheng:$LD_LIBRARY_PATH
教材上演示的也是这种方法。 - 修改sudo vi /etc/ld.so.conf,添加库路径在文件中,sudo ldconfig -v (加-v的话是动态显示加载过程,不加也行)
sudo vi /etc/ld.so.conf(在这里面添加路径)
sudo ldconfig -v (加-v的话是动态显示加载过程,不加也行)
然后输入echo $LD_LIBRARY_PATH
,会显示用户在/etc/ld.so.conf中添加的路径。
-
问题2:
解决方案:加上-Iinclude
参数即可
-
问题3:在运行生成的可执行文件时出现段错误
解决方案
在编译过程忘记加对应参数了……加上-tx -tc xxx就可以正常运行。