fread如何真正起作用?

Beg*_*ner 72 c fread

声明fread如下:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
Run Code Online (Sandbox Code Playgroud)

问题是:两个这样的调用的阅读性能是否存在差异fread:

char a[1000];
Run Code Online (Sandbox Code Playgroud)
  1. fread(a, 1, 1000, stdin);
  2. fread(a, 1000, 1, stdin);

它会读取1000字节一次,每次?

Kei*_*son 101

表现可能有差异,也可能没有差异.语义有所不同.

fread(a, 1, 1000, stdin);
Run Code Online (Sandbox Code Playgroud)

尝试读取1000个数据元素,每个数据元素长度为1个字节.

fread(a, 1000, 1, stdin);
Run Code Online (Sandbox Code Playgroud)

尝试读取1个1000字节长的数据元素.

它们是不同的,因为它fread()返回它能够读取的数据元素的数量,而不是字节数.如果在读取完整的1000个字节之前它到达文件结尾(或错误条件),则第一个版本必须准确指出它读取的字节数; 第二个失败并返回0.

实际上,它可能只是调用一个低级函数,它试图读取1000个字节并指示它实际读取的字节数.对于较大的读取,它可能会进行多个较低级别的调用.要返回的值的计算fread()是不同的,但计算的费用是微不足道的.

如果实现可以在尝试读取数据之前判断没有足够的数据可供读取,则可能存在差异.例如,如果您正在读取900字节的文件,则第一个版本将读取所有900个字节并返回900,而第二个版本可能无法读取任何内容.在这两种情况下,文件位置指示符都按成功读取的字符数提前,即900.

但总的来说,你应该根据你需要的信息选择如何调用它.如果部分读取并不比不读取任何内容更好,则读取单个数据元素.如果部分读取有用,则读入较小的块.

  • 没关系,找到了。C11 在 7.21.8.1.2 和 7.21.8.2.2 中表示:_如果发生错误,则流的文件位置指示符的结果值是不确定的。_ (3认同)
  • POSIX 规范要严格得多……它要求 fread 为每个对象确定 fgetc 的大小,因此在任何一种情况下都将完成完全相同数量的 fgetc(但返回值会有所不同)。 (2认同)

Arj*_*kar 17

根据说明书,这两者可以通过实施方式区别对待.

如果您的文件小于1000字节,fread(a, 1, 1000, stdin)(读取1000个元素,每个1字节)仍将复制所有字节,直到EOF.另一方面,未指定fread(a, 1000, 1, stdin)存储的(读取1个1000字节元素)的结果a,因为没有足够的数据来完成读取"第一个"(且仅)1000字节元素.

当然,某些实现仍然可以根据需要将"部分"元素复制到尽可能多的字节中.


ken*_*ytm 14

这将是实施细节.在glibc中,两者在性能上是相同的,因为它基本上实现为(参考http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iofread.c):

size_t fread (void* buf, size_t size, size_t count, FILE* f)
{
    size_t bytes_requested = size * count;
    size_t bytes_read = read(f->fd, buf, bytes_requested);
    return bytes_read / size;
}
Run Code Online (Sandbox Code Playgroud)

注意C 和POSIX标准不保证size每次都需要读取完整的大小对象.如果无法读取完整对象(例如,stdin只有999字节,但您已请求size == 1000),则文件将保持在一个间隔终止状态(C99§7.19.8.1/ 2).

编辑:查看关于POSIX的其他答案.


Nee*_*asu 6

freadgetc内部调用。在Minix次数getc被称为仅仅是size*nmemb那么多少次getc将被称为依赖于产品的这两个。所以无论fread(a, 1, 1000, stdin)fread(a, 1000, 1, stdin)运行getc 1000=(1000*1)时间。这是fread来自 Minix的简单实现

size_t fread(void *ptr, size_t size, size_t nmemb, register FILE *stream){
register char *cp = ptr;
register int c;
size_t ndone = 0;
register size_t s;

if (size)
    while ( ndone < nmemb ) {
    s = size;
    do {
        if ((c = getc(stream)) != EOF)
            *cp++ = c;
        else
            return ndone;
    } while (--s);
    ndone++;
}

return ndone;
}
Run Code Online (Sandbox Code Playgroud)