关键词
restrict官方库
limits
CHAR_BIT
CHAR_BIT 宏描述了当前系统一个byte包含几个bit
常用宏
offsetof
1 | #define offsetof(type,member)((size_t)&((type*)0)->member) |
解析:
0
(type)0 强行将0作为type类型的指针
((type)0)->member 获取member对象
&((type)0)->member 获取membe对象地址
(size_t)&((type)0)->member 将地址转化为size_t
文件I/O
文件
文本视图和二进制视图
通常对于文本文件使用文本视图,对二进制文件使用二进制视图,但是对于同一个文件,其存储的内容是一致的,关键在于怎么解析看待这个文件,一个文本文件也可以解析为二进制文件
在文本视图中,程序所看到的内容和文件的内容会有所不同
解释: C语言会对当前操作系统环境对文本信息做不同的解析,如写入一个换行符都写入了\n,如果操作系统是windows则是写入\n\r,linux则是\r
I/O级别
- 低级别I/O,由操作系统提供的I/O服务
- 高级别I/O,由ANSI C提供的C语言标准I/O服务
优劣势:
- 标准I/O提供多个专用函数
- 标准I/O自带缓冲区
标准文件
- 标准输入 stdin 读取默认的输入设备(p.s.键盘)
- 标准输出 stdout 写入默认的标准输出(p.s.显示屏)
- 标准错误 stderr 写入默认的标准输出(p.s.显示屏)
函数众
说道这里,有点无聊,来个程序先嗨一发,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main(int argc, char* argv[]) {
int ch;
FILE* fp;
long count;
if(argc != 2) {
printf("intput the file u want to open!");
exit(0);
}
if((fp = fopen(argv[1],"r")) == NULL){
printf("open file %s failed!", argv[1]);
exit(0);
}
while((ch = getc(fp)) != EOF) {
putc(ch, stdout);
count++;
}
fclose(fp);
printf("File %s has %d characters",argv[1], count);
exit(0);
}
这个程序是干什么的,
- 从命令行接收参数,参数为要打开的文件
- 打开相应的文件,将文件内容再输出到标准输出里,并统计文件内的字符数
运行结果:
./count count.cfopen
一本正经的函数声明:1
FILE * fopen(const char * path, const char * mode);
传参说明
path:很easy,文件路径,默认在当前执行文件路径查找
| mode | 意义|
| :——– | ——–:|
| r| 可读|
| w| 可写,可创建|
| a| 可追加,可创建|
| r+| 可读写|
| w+| 可读写,若问件存在,则初始化为0|
| a+| 可读追加写,可以新建|
| rb,wb,ab,ab+,a+b,wb+,w+b,ab+,a+b| 类似于上面,二进制模式|
额 好多,剩下的自己查
p.s. 注意带有w的都会把原先的内容清空掉,谨慎,谨慎
返回参数说明
FILE类型
- 文件指针
- 不指向实际文件,而是指向一个文件的数据包(包含文件的各种信息,包括缓冲区,)
以上为C primer pluse的解释 那么FILE到底是如何定义的呢!
找到系统/usr/include/stdio.h下1
typedef struct _IO_FILE FILE;
将struct _IO_FILE 解析成了FILE再追,查到_IO_FILE在libio.h里1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is 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;
int _blksize;
int _flags2;
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
/* 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;
};
好吧,有点小复杂,不深究了。
getc putc
1 | int getc(FILE *stream) |
与getchar() putchar()类似 就是把输入输出可以重定位了,不只是标准输入输出
文件末尾的问题:getc()在读取一个文件末尾的时候,将会返回特殊值EOF,所以C语言只有在读到超过文件末尾的时候才能判断文件的末尾,所以为了避免读到空文件,对文件末尾的判断要加在循环开始的地方
puts
1 | int puts(const char *string); |
将字符串输出到标准输出上
fclose()
1 | int fclose( FILE *fp ); |
返回值 0关闭成功 其余关闭失败
关闭一个文件流,简单易懂
但是也可能出现关闭失败的现象,比如移动硬盘被拔了,磁盘满了
fprintf fscanf
1 | int fprintf (FILE* stream, const char*format, [argument]) |
rewind
1 | void rewind(FILE *stream); |
将文件流指针移到开始