fwrite和fread函数参数中size和nmemb

我喜欢使用C语言中读写文件的两个函数fread和fwrite,而不喜欢使用C++中的ifstream和ofstream类,一来用起来感觉麻烦,二来运行效率还低。

一直对fread和fwrite的参数列表中的size和nmemb很迷惑,你看系统API函数write的定义:

ssize_t write(int fd, const void *buf, size_t count);

一看就能明白,向文件中写数据,文件是fd,数据地址为buf,长度是count个字节。而fwrite的就不一样,如下:

size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);

文件是stream,数据地址为ptr,长度却是nmemb个size大小,为嘛不弄成size * nmemb成一个参数,而要弄成两个。我开始以为是跟位置对齐有关,而且认为

fwrite(ptr, 1, 4096, fp);

会比

fwrite(ptr, 4096, 1, fp);

效率高。今天查了一下glibc源码,才知道,这种理解是错误的,这么搞两个参数跟效率无关,而跟返回结果有关。先直接上源码,注意fwrite的具体实现是这个叫_IO_fwrite的函数:

_IO_size_t
_IO_fwrite (buf, size, count, fp) 
     const void *buf;
     _IO_size_t size;
     _IO_size_t count;
     _IO_FILE *fp;
{
    _IO_size_t request = size * count;
    _IO_size_t written = 0;
    CHECK_FILE (fp, 0); 
    if (request == 0)
        return 0;
    _IO_acquire_lock (fp);
    if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1) 
        written = _IO_sputn (fp, (const char *) buf, request);
    _IO_release_lock (fp);
    /* We have written all of the input in case the return value indicates
       this or EOF is returned.  The latter is a special case where we
       simply did not manage to flush the buffer.  But the data is in the
       buffer and therefore written as far as fwrite is concerned.  */
    if (written == request || written == EOF)
        return count;
    else
        return written / size;
}

从源码可以看到,两个参数传进去之后,还是算了size * count,所以与效率无关。而在返回时,如果整个都写成功,那就返回count,否则返回written / size,总之返回的是成功写入的块数,而不是字节数(除非size为1)。好处是写入多个结构体时,返回值能告诉你成功写入的结构体的个数,这只是让调用者方便了些许而已,如果调用者关心的是全部是否写成功,那么完全没必要纠结于是1, 4096还是4096, 1。fread参数列表一样,道理一样。

通过源码还可以注意到,写文件是有加锁的。而且写是不会因为遇到EOF而失败的,遇到EOF是因为没有清buffer,但数据肯定是到buffer了。fputs可以算是一个参数简化版的fwrite,看看实现代码就能明白了:

int
_IO_fputs (str, fp) 
      const char *str;
      _IO_FILE *fp;
{
    _IO_size_t len = strlen (str);
    int result = EOF;
    CHECK_FILE (fp, EOF);
    _IO_acquire_lock (fp);
    if ((_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1) 
            && _IO_sputn (fp, str, len) == len)
        result = 1;
    _IO_release_lock (fp);
    return result;
}
发表于 2013年07月20日 12:32   评论:0   阅读:4851  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo