11.5.3 fread_nolock_s(1)
fread_nolock_s是进行实际工作的函数,为了便于理解,下面会分段列出fread_nolock_s的实现,并且将省去所有的参数检查和错误检查。同样,还将省去64位部分的代码。
fread -> fread_s -> _fread_nolock_s: size_t __cdecl _fread_nolock_s( void *buffer, size_t bufferSize, size_t elementSize, size_t num, FILE *stream ) { char *data; size_t dataSize; size_t total; size_t count; unsigned streambufsize; unsigned nbytes; unsigned nread; int c; data = buffer; dataSize = bufferSize; count = total = elementSize * num; |
这一段是fread_nolock_s的初始化部分。在它的局部变量中,data将始终指向buffer中尚未被写入的起始部分。在最开始的时候,data指向buffer的开头。dataSize记录了buffer中还可以写入的字节数,理论上,data + dataSize = buffer + bufferSize。如图11-12所示。
|
| (点击查看大图)图11-12 data、buffer、bufferSize和dataSize |
total变量记录了总共须要读取的字节数,count则记录在读取过程中尚未读的字节数。streambufsize记录了文件缓冲的大小。剩下的3个局部变量在代码的分析过程中会一一提到。在这里需要特别提一下缓冲在FILE结构中的具体实现。
在对缓冲的概念有了一定了解之后,可分析一下文件类型FILE结构的定义了。FILE的定义位于stdio.h里:
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE;
|
在这里,_base字段指向一个字符数组,即这个文件的缓冲,而_bufsiz记录着这个缓冲的大小。_ptr和fread_nolock_s的局部变量data一样,指向buffer中第一个未读的字节,而_cnt记录剩余未读字节的个数。_flag记录了FILE结构所代表的打开文件的一些属性,目前我们感兴趣的是3个标志:
#define _IOYOURBUF 0x0100 #define _IOMYBUF 0x0008 #define _IONBF 0x0004 |
在这里,_IOYOURBUF代表这个文件使用用户通过setbuf提供的buffer,_IOMYBUF代表这个文件使用内部的缓冲,而_IONBF代表这个文件使用一个单字节的缓冲,即缓冲大小仅为1个字节。这个缓冲就是_charbuf变量。此时,_base变量的值是无效的。接下来继续看fread_nolock_s的代码:
if (anybuf(stream)) { streambufsize = stream->_bufsiz; } else { streambufsize = _INTERNAL_BUFSIZ; } |
anybuf函数的定义位于file2.h:
#define anybuf(s) \ ((s)->_flag & (_IOMYBUF|_IONBF|_IOYOURBUF)) |
事实上anybuf并不是函数,而是一个宏,它仅检查这个FILE结构的_flag变量里有没有前面提到的3个标志位的任意一个,如果这3个标志位在_flag中存在任意一个,就说明这个文件使用了缓冲。
【责任编辑:
云霞 TEL:(010)68476606】