2021-2022-diocs-MyOD

20191218 2021-2022-diocs-MyOD

一、任务详情

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

二、实践过程

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]=='\n')
            {
                printf("\\n  ");
            }
            else
            {
                printf("%c \t",str[j]);
            }
        }
        printf("\n");
//输出文本
        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("字符数太大,超出限制\n");
        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("\n");
    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("  \t");
        }
        printf("\n");
}

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编译。

解决办法:

  1. 拷贝到系统的库路径下(不推荐)
  2. 修改LD_LIBRARY_PATH环境变量,将库所在的路径添加到环境变量中,用冒号分割。
    假设libfile.so在/root/LProject_20191218TangQiheng中
    export LD_LIBRARY_PATH=//root/LProject_20191218TangQiheng:$LD_LIBRARY_PATH

    教材上演示的也是这种方法。
  3. 修改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中添加的路径。

参考博客Linux中静态库和动态库的制作及发布

  • 问题2
    解决方案:加上-Iinclude参数即可

  • 问题3:在运行生成的可执行文件时出现段错误

    解决方案
    在编译过程忘记加对应参数了……加上-tx -tc xxx就可以正常运行。

posted @ 2021-09-24 21:11  Ensoleile  阅读(52)  评论(0编辑  收藏  举报