簡體   English   中英

C語言中的fread實際上如何工作?

[英]How does fread in C actually work?

我了解fread()具有以下函數定義:

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

我也了解inptr是使用fopen()函數打開FILE指針時返回的文件指針。 我的問題是inptr是否在文件的內存中存儲文件的每個單個字符/字母的內存地址? 如果是這種情況,是否inptr的內存地址復制到*buffer (指向緩沖區數組的指針)?

我還有另一件事感到困惑。 每次調用fread() ,將復制/傳輸內存的size * qty字節。 inptr本身指向的文件內容,還是被復制/傳輸的文件內容的內存地址?

如果有人可以幫助我清除混亂,將不勝感激。 謝謝 :)

FILE是由您的操作系統實現的。 FILE上運行的功能由您的系統實現。 你不知道 要知道,您需要瀏覽操作系統的源代碼。
inptr可能是操作系統分配的內存的指針。 或它可能是一個數字,您的操作系統用來查找它的數據。 無論如何,這是系統用來查找FILE特定數據的句柄。 然后您的系統決定該數據中包含什么。 出於緩存目的,也許所有字母都緩存在某個緩沖區中。 也許不吧。
FREAD調用。 Freadinptr句柄后面的基礎實體讀取數據。 inptr會解釋inptr ,以訪問基礎內存或結構或設備或硬盤驅動器或打印機或鍵盤或鼠標或其他任何內容。 它讀取qty*size個字節的數據。 這些數據放在buffer 沒有指針放置在那里。 從設備讀取的字節被放置在buffer指向的內存中。

您的問題有點令人困惑(這可能就是您要問他們的原因),所以我會盡力回答。

FILE *inptr是打開文件的句柄。 您沒有直接閱讀它,它只是用來告訴相關功能進行哪些操作。 您可以將其想像成人類讀的文件夾中的文件名,該文件名用於標識文件,但是以另一種方式訪問​​內容。

至於數據,它是從用fopen()打開的文件中讀取的,並隨后提供了文件句柄。 數據不直接與FILE指針相關,通常,您不應該直接弄亂FILE指針(不要嘗試直接從中讀取/寫入數據)。

我試着對操作不太熟練,因為您似乎對C還是陌生的,但只是將FILE *視為計算機在內部“命名”文件以供自己使用的方式,以及數據緩沖區僅僅是內容。

您可以將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);
}

問題的答案,

“ fread()如何工作?”

基本上是

“它要求您的操作系統為您讀取文件。”

操作系統內核或多或少的唯一目的是代表您執行類似的操作。 內核托管磁盤和文件系統的設備驅動程序,並且無論文件存儲在什么位置(例如FAT32格式的HDD,網絡共享等),都能夠為您的程序獲取數據。

fread()要求操作系統從文件中獲取數據的方式在OS和CPU之間略有不同。 回到MS-DOS的美好時光,fread()函數會將各種參數(根據程序給fread()的參數計算)加載到CPU寄存器中,然后引發中斷。 然后實際上是MS-DOS的一部分的中斷處理程序將去獲取請求的數據,並將其放置在內存中的給定位置。 MS-DOS手冊指定了要加載的寄存器和引發的中斷。 傳遞給fread()的參數是系統調用所需參數的抽象。

這就是所謂的系統調用。 每個操作系統都有一個系統調用接口。 Linux上的glibc之類的庫提供了方便的功能,如fread()(這是標准C庫的一部分),並為您進行系統調用(這在操作系統之間未標准化)。

請注意,這意味着glibc不是操作系統的基本部分。 它只是一個例程庫,可圍繞Linux提供的系統調用實現C標准庫。 這意味着您可以使用替代的C庫。 例如,即使Android具有Linux內核,它也不使用glibc。

在Windows上類似。 Windows中的所有軟件(C,C ++ 、. NET運行時等)均編寫為使用WIN32 API庫(win32.dll)。 在Windows上的區別是NT內核系統調用接口沒有發布。 我們不知道這是什么。

這導致了一些有趣的事情。

  • Linux上的WINE將重新創建WIN32.dll,而不是NT內核系統調用接口。
  • Windows 10上適用於Linux的Windows子系統會重新創建Linux系統調用界面(這是可能的,因為它是公共知識)。
  • Solaris,QNX和FreeBSD具有相同的技巧。
  • 更奇怪的是,看起來MS已為Linux完成了NT內核系統接口填充程序(即WINE尚未完成的工作),以允許MS-SQLServer在Linux上運行。 這實際上是Windows的Linux子系統。 他們還沒有放棄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM