SSDsim源码分析之 load_parameters

这篇博文将继续分析SSDsim的初始化过程,主要的分析对象函数是这个load_parameters()函数,接下来让我们分析下这个函数的主要框架以及给出相应的源码注释。

load_parameters()函数的主要功能

load_parameters函数的主要功能是负责将参数文件parameter中的SSD相关设置参数一一传输至ssd->parameters这个结构体定义中。其中,load_parameters函数接收了一个参数文件名的函数参数,然后在函数内部申请了一部分缓冲区buf作为数据缓存处理的区域。而后通过fget()函数打开parameter_file文件并且在buf中逐一逐行进行数据的读取和相应的保存,由于参数文件中关于SSD参数的格式都规定为:* = *这样的固定格式,所以通过这种逐行读取可以实现对特定字符串参数的读取从而设置ssd->parameters中的相关参数。对于各个参数的判断该函数使用了一个多分支if-else的判断结构,每一次fget()一行数据后都会截取相应的字符串数据然后在这个if判断结构中进行验证和设置。

当文件读取完毕后,函数便开始清理buf缓冲区并且关闭相关的打开文件指针。

相关的源码注解

struct parameter_value *load_parameters(char parameter_file[30])
{
    FILE * fp;          //fp相当于指向某一个文件的一个指针,FILE类型是stdio头文件的一种结构体变量,代表指向文件的类型
    FILE * fp1;
    FILE * fp2;
    errno_t ferr;           //errno_t类型可以简单理解为int类型,用于判断打开文件的判定条件
    struct parameter_value *p;      
    char buf[BUFSIZE];      //初始化用到的缓存区
    int i;
    int pre_eql,next_eql;   //pre_eql变量是代表了buf缓冲区内=之前的其他字符数量,相当于位置;next_eql变量则代表了=后下一个字符的位置
    int res_eql;            //用于在参数检查中作判断之用,利用了strcmp函数返回的值判断参数是否正确
    char *ptr;              //ptr负责记录 = 出现的位置

    p = (struct parameter_value *)malloc(sizeof(struct parameter_value));   //动态分配并初始化p的内存空间
    alloc_assert(p,"parameter_value");
    memset(p,0,sizeof(struct parameter_value));     //清零

    p->queue_length=5;      //请求队列最长为5
    memset(buf,0,BUFSIZE);  //缓冲区内存清零

/************************************************************************************************
关于fopen_s函数的原型:
errno_t fopen_s( FILE** pFile, const char *filename, const char *mode );
这个函数接收的第一个函数参数了代表了打开的文件指针指向的地址(由于是指针的指针,所以这个文件指针地址
是指向了一个指针也就是一个特定的地址),文件名,以及访问的类型;如果成功返回0,失败则返回相应的错误代码。

主要的访问类型mode属性有:
"r":打开以进行读取。如果该文件不存在,或无法找到,fopen_s调用失败。

"w":打开一个空文件以进行写入。如果该文件存在,其内容将被销毁。   

下面分别用了三个FILE文件指针打开了参数文件并且实现了指向了三个文件,分别是参数文件、参数名文件、参数值文件
************************************************************************************************/
    if((ferr = fopen_s(&fp,parameter_file,"r"))!= 0)        //fopen_s函数作用是读取parameter_file并且让fp指向它,r是代表只读文件,结果正确则返回一个0
    {                                                       
    //如果打开失败;(原因可能找不到这个文件或者文件不存在)
        printf("the file parameter_file error!\n"); 
        return p;
    }
    if((ferr = fopen_s(&fp1,"parameters_name.txt","w"))!= 0)    //之前定义的3个文件指针在此处都用到了,作用就是将相应的文件指针分别指向三个文件流,第一个是只读,第二和第三是可写,即fp只需读数据,而fp2和fp3需要写入数据
    {                                                           //打开一个内容为空的参数名文件并且将fp1文件指针指向的地址内容写入到这个文件中
        printf("the file parameter_name error!\n");             //如果打开失败则返回并显示错误信息
        return p;
    }
    if((ferr = fopen_s(&fp2,"parameters_value.txt","w")) != 0)
    {   
        printf("the file parameter_value error!\n");            //打开一个内容为空的参数值文件并且将fp2文件指针指向的地址内容写入到这个文件中
        return p;
    }

/************************************************************************************************
关于fgets()函数的原理:
函数原型:char *fgets(char *buf, int bufsize, FILE *stream);

参数

*buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明存储数据的大小。
*stream: 文件结构体指针,将要读取的文件流。

从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),
如果文件中的该行,不足bufsize个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,
但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets
的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断。

stream文件流指针体指向文件内容地址的偏移原则
如果使用fgets()读取某个文件,第一次读取的bufsize为5,而文件的第一行有10个字符(算上'\n'),那么读取文件的指针会偏移至当前读取完的这个字符
之后的位置。也就是第二次再用fgets()读取文件的时候,则会继续读取其后的字符。而如果使用fgets() 读取文件的时候bufsize大于该行的字符总数加2
(多出来的两个,一个保存文件本身的'\n'换行,一个保存字符串本身的结束标识'\0'),文件并不会继续读下去,仅仅只是这一行读取完,随后指向文件的指针
会自动偏移至下一行。

************************************************************************************************/

    /*
    fgets函数是每次按行读取的,如果bufsize大于当前行的字符数量,那么将逐一读取所有行的数据,所以这里可以用fgets函数的返回值作为while循环的判断条件,这里fgets会读取200个字节大小的
    内容到buf缓冲区中,但是如果fp指向的文本文件(ssdsim中的参数文件就是以txt文本保存的)按照分行参数设置的规则的话,那这里fgets读完一行内容后
    就会继续读下一行的内容,每次都会将当前行中的200字节(如果有200字节长度)内容都读到buf中。
    如果bufsize小于当前行的字符数量,那么这个函数会读取bufsize-1个字符到buf中,此时读取文件的指针会自动指向了第bufsize个字符的位置也就是当前
    读取完毕的最后一个字符之后的那个位置。
    */

    while(fgets(buf,200,fp)){               //fgets()函数的作用是将fp指向的文件内容读取200个字节的数据到buf数组中,返回值是char buf[0]
        if(buf[0] =='#' || buf[0] == ' ') continue; //如果参数文件的第一个数据是#或者是空字符则直接结束本次循环,执行下一步循环
        ptr=strchr(buf,'=');        //strchr函数的作用是查找第一次出现'='的buf位置,返回值是char*即首次出现=的位置
        if(!ptr) continue;      //此处之所以要判断=处的位置,初步猜测是由于参数文件内相关的参数文件是以"chip number=**"这样的格式存放的,所以要一一判断出所有的参数

        pre_eql = ptr - buf;    //pre_eql变量是代表了buf缓冲区内=之前的其他字符数量,相当于位置
        next_eql = pre_eql + 1;     //next_eql变量则代表了=后下一个字符的位置

        while(buf[pre_eql-1] == ' ') pre_eql--; //若=前面的位置字符是空格,则一直向前推进直到pre_eql所指的位置字符非空格,这种方式避免了诸如 chip number = **这样的参数所带来的处理问题
        buf[pre_eql] = 0;                       //令=前面的非空格字符的后一个字符为0,如果=之前没有空格则是将=赋值为0
        //之所以这里要将非空格字符后赋值为0是因为在下面的strcmp字符串比较函数中,strcmp只有在字符串中遇到\0才会停止比较
        /**************************************************************************************************************
        下面的if多分支结构的作用是负责在buf缓冲区中逐一读取到相关参数值并且将"="后面相关的参数值读入到ssd中(这里的ssd就是指p所指的成员);
        所以这里的整个if多分支结构就实现了在while循环中反复读取参数到ssd中

        sscanf函数的相关原型:
        int sscanf(const char *buffer,const char *format,[argument ]...);
        buffer:存储的数据
        format格式控制字符串
    
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值