c语言FILE结构和字符串读取
软件:gcc 版本 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
本文通过FILE结构在 stdio.h中的定义, 解析c语言对标准输入和文件输入的实现,有助于深入理解和使用stdio.h 中的函数。
1 FILE结构
1.1 /usr/include/stdio.h
49行
typedef struct _IO_FILE FILE;
75行
#include <libio.h>
164-167行
/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
stdio.h文件的49行和164-167行显示:标准输入stdin、标准输出stdout和标准错误stderr,均为FILE结构的指针。
FILE结构的具体定义在文件libio.h中。
1.2 /usr/include/libio.h
123-138行
#define _IO_USER_BUF 1 /* User owns buffer; don't delete it on close. */
#define _IO_UNBUFFERED 2
#define _IO_NO_READS 4 /* Reading not allowed */
#define _IO_NO_WRITES 8 /* Writing not allowd */
#define _IO_EOF_SEEN 0x10
#define _IO_ERR_SEEN 0x20
#define _IO_DELETE_DONT_CLOSE 0x40 /* Don't call close(_fileno) on cleanup. */
#define _IO_LINKED 0x80 /* Set if linked (using _chain) to streambuf::_list_all.*/
#define _IO_IN_BACKUP 0x100
#define _IO_LINE_BUF 0x200
#define _IO_TIED_PUT_GET 0x400 /* Set if put and get pointer logicly tied. */
#define _IO_CURRENTLY_PUTTING 0x800
#define _IO_IS_APPENDING 0x1000
#define _IO_IS_FILEBUF 0x2000
#define _IO_BAD_SEEN 0x4000
#define _IO_USER_LOCK 0x8000
271-312行
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
libio.h中271-312行定义了FILE结构, 123-138行定义了FILE结构中_flags状态标志的各个位的含义, 如_IO_EOF_SEEN对应的位标志文件是否结束。
FILE结构默认的输出缓冲区大小为4096个字符,缓冲区对应的指针作用如下:
缓冲区指针 | 作用 |
---|---|
_IO_read_base | 指向从文件中载入到输入缓冲区的所有字符中的第一个; |
_IO_read_ptr | 指向当前缓冲区中第一个未被读取的字符,当ptr==end时, 表示输入缓冲区已为空,此时再对文件进行读取, EOF标志会被设置,并且这六个指针全部置为base指针的值; |
_IO_read_end | 指向从文件中载入到输入缓冲区的 所有字符中的最后一个的下一个位置; |
_IO_write_base | 指向输出缓冲区的基地址; |
_IO_write_ptr | 指向当前输出缓冲区最后一个字符的下一个位置, ptr==end时进行写入,会把缓冲区的数据输出到文件, 然后ptr=base,再将字符写到ptr位置; |
_IO_write_end | 指向当前输出缓冲区的最后一个位置。 |
2 字符串读取
函数原形 | 注意点 |
---|---|
int fgetc ( FILE * stream ); | 返回值为int类型,读取成功,返回读取字符; 当文件流已置EOF标志时,返回EOF(-1); 遇到读取错误时,置错误标志,返回EOF。 |
int getc ( FILE * stream ); | 功能与fgetc相同,但在一些实现里,getc为一个宏。 |
int getchar ( void ); | 功能与getc(stdin)相同。 |
int fputc ( int character, FILE * stream ); | 写入成功时,返回character; 遇到写入错误时,置错误标志,返回EOF。 |
int putc ( int character, FILE * stream ); | 功能与fputc相同,但在一些实现里,putc为一个宏。 |
int putchar ( int character ); | 功能与putc(character, stdout)相同。 |
char * fgets ( char * str, int num, FILE * stream ); | 读取num-1个字符,或者遇到newline字符,或者遇到文件结束时停止读取。 newline会作为有效字符存入str中。str以NULL结束。 读取成功返回str; 当一开始就遇到文件结束,返回NULL,str内容不变; 当遇到error,返回NULL,str会被改变。 |
char * gets ( char * str ); | 读取时遇到newline字符,或者遇到文件结束时停止读取。gets可能会溢出,一个bug。 newline被抛弃,不会被作为有效字符存取str中,str以NULL结束。 返回与fgets相同。 |
int fputs ( const char * str, FILE * stream ); | 将字符串str写入stream,直到遇到NULL,NULL不会被写入stream。与puts不同。 写入成功返回非负数;写入错误时,置错误标志,返回EOF。 |
int puts ( const char * str ); | 在fputs基础上,puts会多写入一个newline。 |