现在的位置: 首页 > 综合 > 正文

自己制作的数据存入和读取系统

2013年06月01日 ⁄ 综合 ⁄ 共 3850字 ⁄ 字号 评论关闭

自己制作的数据存入和读取系统

作者:蒋轶民  创作于20112921:56:46

以前我就想制作一个简单的属性脚本系统,但是由于自己经验不足而且课程又比较紧,所以我一直都没有成功。那一次我做了一天,虽然没有成功,但是也获取了一点经验。我写了一篇技术文章,讲的是fprintf()函数的原理和自己的一个实践。

       以下是上次文章的部分摘要:

 

c/c++入门的人一定知道可变参数函数。这种函数的特征有二:第一是至少有一个固定参数,第二,可变参数部分总是在固定参数的后面。如我写的函数:

bool PutValue( const char* fmt, ... );

就是这样一种可变参数函数。高手们可定能够熟练地使用va_start()va_arg()va_end()宏了,因为他们是可变参数的“三剑客”。有了它们,稍微有些c语言知识就能够编出高效的可变参数函数了。但我还是不知足,我要了解这些宏的实现原理。现在把stdarg.h中的相关定义展示给大家。

typedef char *va_list;

 

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

 

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

#define va_end(ap) ( ap = (va_list)0 )

 

       从中看出,这些宏有些生涩难懂。我都是在复习了c语言位运算和原码、补码知识后才看得懂的。如果大家感兴趣的话,可以看看相关的知识。

       然后我们知道,使用windows操作系统和intelCPU,栈是自顶向下的。也就是说栈顶在低位地址,栈底在高位地址。在传递参数的时候,通过调用默认的调用规范__cdecl,参数的传递顺序是从右到左。最终的结果是最左边第一个参数处于最低地址处,最右边最后一个参数处于最高的地址处。而使用...编译器又不会报错。于是我们想可不可以通过第一个参数的地址找到所有的参数呢?答案是肯定的。

       但是我在这里遇到一个难以解决的问题:对于float类型参数似乎不起作用。因为得出的不是我想要的答案。这又该如何解决呢?我在网上查到了相关的问题,原来是charshortfloat得到了提升,也就是“加宽”。因为intelCPU的栈元素统一是sizeof(int)字节长。也就是4字节。所以小于4字节的charshort都被提升至4字节了,为了访问的方便。而同样是4字节的float由于某种特殊的考量(其实我也不知道是为什么,可能是提高精度吧。),被提升至了double,也就是8字节的水平。所以在内存中float型占用的空间是8字节。

       使用了VS的调试器查看了内存,并且翻了汇编语言程序设计的IEEE浮点数存储方式,基本上验证我的猜想。于是我对计算机组成原理有了全新的认识(不过我们还没有上这门课)。

那么printf()是怎么实现的呢?

       大家应该猜出来了。printf()函数是靠“%”来对传入的参数个数进行统计的。这并不意味着它能够检测出你的参数个数是否和“%”个数保持一致。如果有这样一个语句:

MyPrintf( "%d,%f,%c", a, b );

且没有引入异常处理机制,那么它的后果是未知的,因为它访问了不该访问的区域。

       讲到这里我应该把自己的仿fprintf()函数给大家展示一下了。这个函数有些长,主要是判断类型用了不少语句,但是这个程序能基本与printf()函数的格式说明一致,我只好这么做了。下面我说明一下各个格式标识符的意思:

%c 字符型(char

%sd 有符号短整型(signed short

%s 字符串型(char*)(未实现)

%us 无符号短整型(unsigned short

%ui 无符号整型(unsigned int

%ud 无符号整型(unsigned int

%ul 无符号长整型(unsigned long

%i 有符号整型(signed int

%d 有符号整型(signed int

%f 浮点型(float

%lf 双精度浮点型(double

%ld 有符号长整型(signed long

%li 有符号长整型(signed long

 

       上述格式标识符使用大写字母也有效。

 

 

       这会儿,我终于用了一天时间制作,四到五天时间调试,现在这个数据存入与读取系统终于成熟了。这次的函数也是一个可变参数函数,函数名叫WriteRead

       以下就是DataManageSystem.h文件。这个头文件相当简单,私有成员只有一个100字节的文件名。

       UpdateSystem()函数和KeyDown()函数声明为内联函数,可以提升程序的运行效率。

       下面就是我的InputSystem.h文件:

在主函数中这样调用:

程序运行结果如下所示:

打开Configure.txt文件,结果如下图所示:

如果我们新建了一个Configure.txt文件,内容是:

再这样调用:

结果如图所示:

下面说说这个存入和读取系统的性能。

这个数据存入和读取系统在读取文件的时候必须要精确匹配,如果任何不匹配的现象,则会返回错误。

如果文本文件很大,那么使用此存入和读取系统连续读取文件的时候,速度会很慢。主要因为每调用一次,就必须打开文件、读取文件和关闭文件。并且文件指针都要回溯。并且这个存入和读取系统无法读取汉字。主要因为iostreamANSI类型的,必须更新这个系统才能适应读取汉字。

这个系统的原理是利用可变参数函数,然后编程自动定址,来进行读取和写入。其实说得很简单,但是做起来就不太容易了,所以说类printf()函数也是凝聚了很多人的努力,要不怎么会成为标准库函数呢?

       接下来我要介绍的是主框架系统。这个系统能为windows程序员提供了一个封装好的类,能快速地开发出win32程序。介于篇幅原因,下一次再来介绍吧。

 

 


 

如果大家没有时间上网看的话,这里有我整理的说明文档:http://download.csdn.net/source/3017097,大家可以下载。

 

抱歉!评论已关闭.