首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 標準庫 stdio.h 源碼閱讀筆記 (一):FILE 結構、流管理、fopen/_getstream 實現剖析

     編輯:關於C語言

歷史背景:從 FORTRAN LUN 到 UNIX 文件描述符

標準 I/O 庫演進:FORTRAN IV 邏輯單元號 (LUN) → UNIX 文件描述符 (小整數) + 標準流 (stdin/stdout/stderr) + 統一文本流格式 (換行符結尾) → C 標準庫繼承並標準化 (ANSI C89)。

FILE 結構體剖析 (MSVC 實現)


typedef struct _iobuf {
    char *_ptr;        // 緩衝區當前位置指針
    int   _cnt;        // 緩衝區剩餘字節數
    char *_base;       // 緩衝區基址
    int   _flag;       // 標誌位 (_IOREAD, _IOWRT, _IORW, _IOBUF, _IOSTRG...)
    int   _file;       // 文件描述符 (底層 handle)
    int   _charbuf;    // 無緩衝時單字符緩衝
    int   _bufsiz;     // 緩衝區大小
    char *_tmpfname;   // 臨時文件名 (tmpfile 用)
} FILE;

關鍵:FILE* 傳遞的是指針,**不可複製結構體副本使用**,因為內部指針 (_ptr, _base) 指向共享緩衝區。

流管理機制:_iob 陣列與 __piob 指針陣列

1. 靜態預置流 (_iob)


#define _IOB_ENTRIES 20
FILE _iob[_IOB_ENTRIES] = {
    {_bufin, _INTERNAL_BUFSIZ, _bufin, _IOREAD | _IOYOURBUF, 0, 0, _INTERNAL_BUFSIZ, NULL}, // stdin (0)
    {NULL, 0, NULL, _IOWRT, 1, 0, 0, NULL}, // stdout (1)
    {NULL, 0, NULL, _IOWRT, 2, 0, 0, NULL}, // stderr (2)
    // ... 剩餘 17 項初始化為 0
};
  • 前 3 項對應標準流,_flag 設置模式
  • stdin 預分配 4096 字節緩衝區 (_INTERNAL_BUFSIZ)

2. 動態流擴展 (__piob)


#define _NSTREAM_ 512  // 最大並發流數
FILE **__piob;         // 指向 FILE* 陣列的指針

// 初始化 (進程啟動時)
__piob = (FILE**)_calloc_crt(_NSTREAM_, sizeof(FILE*));
for (i=0; i<_IOB_ENTRIES; i++) __piob[i] = &_iob[i]; // 掛載靜態流
// 其餘 __piob[20]~__piob[511] 初始為 NULL,按需分配

驗證:fopen 509 個文件 + 3 標準流 = 512 達上限。

_getstream():獲取空閒流槽位


FILE * _getstream(void) {
    for (i=0; i<_nstream; i++) {
        if (__piob[i] == NULL) {                    // 空槽位
            __piob[i] = (FILE*)_malloc_crt(sizeof(_FILEX)); // 分配擴展結構
            // 初始化關鍵字段
            stream->_flag = stream->_cnt = 0;
            stream->_tmpfname = stream->_ptr = stream->_base = NULL;
            stream->_file = -1;
            return (FILE*)stream;
        }
    }
    // 兼容舊版:掃描 _iob 陣列尋找 _flag==0
    return NULL; // 耗盡
}

fopen 核心流程

  1. 參數檢查 (路徑、模式非空)
  2. 調用 _getstream() 獲取 FILE*
  3. 調用 _openfile() 解析模式字串 ("r", "w", "rb"...),設置 _flag (_IOREAD/_IOWRT...),調用底層 open() 獲取文件描述符存入 _file
  4. 返回 FILE*

關鍵洞見

  1. 分層架構:應用 → FILE* (緩衝、格式) → 文件描述符 (內核對象) → VFS → 設備驅動
  2. 緩衝區策略:_ptr/_cnt/_base 三元組實現「指針+計數」高效緩衝,_flag 鎖定讀/寫模式防衝突
  3. 動態擴展:靜態 _iob 保底標準流,動態 __piob 支援大量併發文件
  4. 模式鎖定:首次 I/O 操作根據 _flag 固化流方向 (讀/寫),後續不可隨意切換 (需 fflush/fseek)

下一篇預告

深入 _flsbuf (刷新寫緩衝)、_filbuf (填充讀緩衝)、fread/fwrite 塊操作、fseek/ftell 定位實現、臨時文件機制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved