C中的fread实际上是如何工作的?

C中的fread实际上是如何工作的?,c,pointers,fread,file-pointer,C,Pointers,Fread,File Pointer,我了解fread()具有以下函数定义: size_t fread(void *buffer, size_t size, size_t qty, FILE *inptr); 我还了解到,inptr是一个文件指针,在使用fopen()函数打开文件指针时返回。我的问题是inptr是否将文件中每个字符/字母的内存地址存储在其内存中?如果是这种情况,是否将inptr中的内存地址复制到*缓冲区(指向缓冲区数组的指针) 还有一件事我很困惑。每次调用fread()。是由inptr本身指向的文件内容,还是正在复

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

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

还有一件事我很困惑。每次调用
fread()。是由
inptr
本身指向的文件内容,还是正在复制/传输的文件内容的内存地址


如果有人能帮我消除困惑,我将不胜感激。谢谢:)

文件由您的操作系统实现。在
文件
上操作的功能由您的系统实现。你不知道。要知道,您需要浏览操作系统的源代码。
inptr
可能是指向操作系统分配的内存的指针。或者它可能是一个数字,您的操作系统使用它来查找数据。无论如何,它是一个句柄,您的系统使用它来查找
文件
特定数据。你的系统决定了数据中的内容。出于缓存目的,可能所有字母都缓存在某个缓冲区中。也许不会。

打电话
Fread
inptr
句柄后面的底层实体读取数据
inptr
由您的系统进行解释,以访问底层内存、结构、设备、硬盘驱动器、打印机、键盘或鼠标等。它读取
qty*size
字节的数据。这些数据放在
缓冲区中。那里没有指针。从设备读取的字节被放在缓冲区指向的内存中。你的问题有点让人困惑(这可能就是你问这些问题的原因),所以我会尽力回答

FILE*inptr
是打开文件的句柄。您不直接阅读它,它只是用来告诉相关函数操作什么。你可以把它想象成一个人在文件夹中读取文件名,文件名用来标识文件,但内容是通过另一种方式访问的

至于数据,它是从用fopen()打开的文件中读取的,随后提供了一个文件句柄。数据与文件指针没有直接关联,通常不应该直接干扰文件指针(不要尝试直接读取/写入)


我试着对操作不要太过技术化,因为你似乎对C不太熟悉,但只是把
文件*
看作是计算机内部“命名”文件以供自己使用的方式,而数据缓冲区仅仅是内容。

你可以把
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;
}
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);
}

问题的答案是,

“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 Linux子系统确实重新创建了Linux系统调用接口(这是可能的,因为它是公共知识)
  • Solaris、QNX和FreeBSD采用了相同的技巧
  • 更奇怪的是,看起来微软已经为Linux做了一个NT内核系统接口垫片(也就是说,WINE没有做过的事情),以允许微软SQLServer在Linux上运行。这实际上是一个适用于Windows的Linux子系统。他们没有把这个给别人
我的问题是inptr是否将文件中每个字符/字母的内存地址存储在其内存中?检查
文件
包含的内容,读取此结构的成员。打开
vi/usr/include/libio.h
&查找
文件的定义