C中的fread如何实际工作?

时间:2018-05-13 01:57:31

标签: c pointers fread file-pointer

我理解fread()具有以下函数定义:

size_t fread(void *buffer, size_t size, size_t qty, FILE *inptr);

我也理解inptr是使用fopen()函数打开FILE指针时返回的文件指针。我的问题是inptr是否将文件中每个字符/字母的内存地址存储在内存中?如果是这种情况,请将inptr中的内存地址复制到*buffer(指向缓冲区数组的指针)?

还有一件我感到困惑的事情。每次调用fread()时,都会复制/传输size * qty个字节的内存。它是inptr本身指向的文件的内容,还是正在复制/传输的文件内容的内存地址?

如果有人可以帮助我清除混乱,我将不胜感激。谢谢:))

3 个答案:

答案 0 :(得分:0)

FILE由您的操作系统实施。在FILE上运行的功能由您的系统实现。你不知道。要知道,您需要浏览操作系统的来源 inptr可能是指向操作系统分配的内存的指针。或者它可能是一个数字,您的操作系统用它来查找它的数据。无论如何,它是一个句柄,您的系统用它来查找FILE特定数据。并且您的系统决定该数据中的内容。出于缓存目的,可能所有字母都缓存在某个缓冲区中。也许不是。
fread致电。 Freadinptr句柄后面的基础实体读取数据。 inptr由您的系统解释,用于访问底层内存或结构或设备或硬盘驱动器或打印机或键盘或鼠标或任何东西。它读取qty*size个字节的数据。这些数据放在buffer中。那里没有指针。从设备读取的字节放在buffer指向的内存中。

答案 1 :(得分:0)

你可以认为fread被实现了这样的东西:

size_t fread(char *ptr, size_t size, size_t nitems, FILE *fp)
{
    size_t i;
    for(i = 0; i < size * nitems; i++) {
        int c = getc(fp);
        if(c == EOF) break;
        *ptr++ = c;
}

(我遗漏了返回值,因为在我的简化插图中没有一种很好的方式来展示它。)

换句话说,fread通过反复调用getc()来读取一堆字符。显然,这引出了getc如何运作的问题。

你必须知道的是FILE *指向一种结构,它以某种方式包含一些(不一定是所有)文件字符读入内存的缓冲区。因此,在伪代码中,getc()看起来像这样:

int getc(FILE *fp)
{
    if(fp->buffer is empty) {
        fill fp->buffer by reading more characters from underlying file;
        if(that resulted in end-of-file)
            return EOF;
    }

    return(next character from fp->buffer);
}

答案 2 :(得分:0)

问题的答案,

“fread()如何运作?”

基本上是

“它要求您的操作系统为您读取文件。”

操作系统内核的唯一目的或多或少是代表您执行此类操作。内核托管磁盘和文件系统的设备驱动程序,无论文件存储在何处,都可以为程序获取数据(例如FAT32格式的HDD,网络共享等)。

fread()要求操作系统从文件中获取数据的方式在操作系统和CPU之间略有不同。回到MS-DOS的旧时代,fread()函数会将各种参数(根据程序给fread()的参数计算出来)加载到CPU寄存器中,然后引发中断。中断处理程序实际上是MS-DOS的一部分,然后将获取所请求的数据,并将其放在内存中的给定位置。要加载的寄存器和要引发的中断都是由MS-DOS手册指定的。传递给fread()的参数是系统调用所需的参数。

这就是所谓的系统调用。每个操作系统都有一个系统调用接口。像Linux上的glibc这样的库提供了fread()(它是标准C库的一部分)等便捷功能,并为您调用系统(在操作系统之间没有标准化)。

请注意,这意味着glibc不是操作系统的基本组成部分。它只是一个例程库,它围绕Linux提供的系统调用实现C标准库。这意味着您可以使用替代C库。例如,Android不使用glibc,即使它有Linux内核。

同样在Windows上。编写Windows(C,C ++,.NET运行库等)中的所有软件以使用WIN32 API库(win32.dll)。 Windows的不同之处在于NT内核系统调用接口未发布;我们不知道它是什么。

这导致了一些有趣的事情。

  • Linux上的WINE重新创建WIN32.dll,而不是NT内核系统调用接口。
  • Windows 10上的Windows Subsystem for Linux确实重新创建了Linux系统调用接口(这是可能的,因为它是公共知识)。
  • Solaris,QNX和FreeBSD也采用了相同的技巧。
  • 更奇怪的是,看起来MS已经为Linux做了一个NT内核系统接口垫片(即WINE尚未做过的事情),以允许MS-SQLServer在Linux上运行。这实际上是适用于Windows的Linux子系统。他们没有放弃这一点。