1、C语言中不能再一个函数里面定义别的函数 。所以没有局部函数
2、const int a=5; int const a=5; 两者意义一样 该变量a的值是个常量,不能改变
const int *p;
int const *p ;
const 在*前面表示指向的数据是个常量,指针可以改变
int * const p;
const int *const p;
const 在*后面的表示指向的指针是个常量,值不一定是个常量
一、文件描述符 :出了当前进程就没有意义了
1、关于man命令的使用
man 1 xxx 查shell命令
man 2 xxx 查API
man 3 xxx查库函数
2、我们如何退出程序
(1)在main中return 如果程序正常运行,正常返回 return 0,如果异常退出 则return -1;
(2) (1)不算是比较常规的退出进程方法 ,正式终止进程 应该使用 exit() _exit() _Exit()
关于exit()和_exit()
exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中
简单的说,exit函数将终止调用进程。在退出程序之前,所有文件关闭,缓冲输出内容将刷新定义
_exit终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数
3、阻塞与非阻塞(关于open时候的flag O_NONBLOCK)
(1)如果一个函数是阻塞的,则我们调用这个函数时进程有可能被卡住(阻塞住,实质是该函数执行的条件未成熟,没法执行,得等待时机成熟)
(2)如果一个函数是非阻塞的,我们调用该函数时,该函数会立即返回,但是否完成任务不一定。
(3)阻塞与非阻塞是两种不同的设计思路,并没有好坏。总的来说,阻塞式的结果有保障,但时间没保障。非阻塞式的时间有保障但结果没保障。
(4)操作系统的API或者由API封装成的库函数 有很多本身就是被设计为阻塞式或者非阻塞式的。所以我们应用程序调用这些函数时一定要非常清楚。
(5)我们打开文件的时候默认的是阻塞式的,如果你希望以非阻塞的方式打开文件,则flag中要加O_NONBLOCK方式打开文件。
(6)阻塞与非阻塞只用于设备文件,不用与普通文件
4、O_SYNC
(1)WRITE 阻塞等待底层将缓冲区数据写回硬盘 才返回应用层
(2)无O_SYNC时 只是将内容写进缓冲区即返回。。
(二)、文件读写的一些细节
1、errno 其实就是error number linux操作系统给各种常见错误编号,当函数执行错误时,函数会返回一个特定的错误编号errno 告诉我们到底哪里错了。
2、errno 是OS维护的一个全局变量,任何OS内部函数都可以通过设置errno来告诉上层调用者究竟发生了一个什么错误。
3、errno本身是一个int类型的数字,比如-37,每个不同的错误号对应一个错误信息,linux系统提供了一个函数perror 来输出错误信息。错误信息不用我们提供,直接在出错位置perror("打开文件错误"); //perror()里面是一个字符串
(三)、read和write的 count 参数
1、count 是我们想要读或者写的字节数目
返回值是实际完成的我们要写的或者读的字节数,可能等于要读写的字节数或者小于(未完成)
2、当读写和阻塞非阻塞联合事情就更复杂了。 如果一个函数是阻塞的,我们要读30字节,目前只有20个字节,则读取20个字节时就会阻塞等待剩余的10个字节。
3、要读写的文件很大的时候 应该设置一个合适的一次读写的count数目,循环读写 而不应该一次性读写完
(四)、文件IO效率和标准IO
1、文件IO是指当前所说的open write read 等 API 函数构成的一套用来读写文件的体系 这套体系可疑很好的读写文件但是效率有些低。
2、应用层C语言库提供了一些用来读写文件的函数列表,叫做标准IO,标准IO 由一系列的库函数构成,(f_open,f_close,f_read,f_write),这些标准IO其实是由文件IO封装而成的,(比如f_open内部还是调用了open.)标准IO加了封装主要是为了在应用层增加一个缓冲机制,这样我们通过f_write函数写的内容并不是直接进入内核buf中,而是先进入应用层标准IO库维护的buf中,然后标准IO根据操作系统单词write的最佳count选择最佳的时机来完成write到内核buf中(内核再根据最好的时机去将buf数据写到磁盘上)
(五)linux如何管理文件
1、快速格式化和底层格式化 :
快速格式化:速度很快 ,比如格式化一个32G硬盘只需要1秒 底层格式化比较慢
两者的差别:快速格式化只是删除了inode信息,并没有删除数据,有可能还原格式化后的硬盘。 底层格式化则是将数据删除了,基本上是不可能还原数据的。
2、文件与流
(1)流(stream) 文件读出或者写入时只能一个字符一个字符的操作,这样就够成了一个流。
(2)流这个概念是动态的,不是静态的
(3)编程中提到的流是与IO相关的,所以叫IO流。文件操作时就构成一个IO流。
3、lseek
当打开一个空文件时,默认情况是文件指针指向文件流开始,所以这时候去write是从文件开头写的。
write 和 read函数值自带移动文件指针。如果读写NGe字节,则文件指针后移N个字节
如果想要随意移动文件指针 则需使用lseek
*****当调用lseek移动文件指针之后,再去调用read和write函数则从移动后的文件指针开始。
4、stdin stdout stderr 对应描述符是0 ,1 , 2标准输入 标准输出 标准错误
printf 默认输出到标准输出 fprintf则可以指定输出到那个文件描述符中
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
(六)文件共享的问题
1、文件多次打开
普通文件可以被重复打开 重复打开一个相同的文件。两个不同的fd,对其读写 是分别读和分别写
如果希望是接续写读 则 在open时候flag 时候|O_APPEND 为什么加O_APPEND就可以接续写呢 关键核心是文件指针
http://edu.csdn.net/course/detail/2401/37561?auto_start=1 第九课 文件重复打开
2、何为文件共享
(1)文件共享就是,同一个文件(同一个文件即同一个inode,相同的路径名)被多个独立的读写体(可以理解为多个文件描述符)去同时(一个文件打开但是尚未关闭就去执行另一个操作)操作。
(2)文件共享的意义有很多:比如我们可以通过多线程同时去操作一个大文件,提高读写效率。
3、文件共享的核心是如何弄出来多个文件描述符指向同一个文件
常见的方法有三种:(1)同一个进程多次使用open打开同一个文件(fd不相同)。。(2)是在不同的进程中去使用open打开同一个文件(两个进程的fd有可能相同有可能不同) (3)linux 内核提供了一个API dup()和 dup2()让进程复制文件描述符(dup复制文件描述符,但是赋值出来的fd2是与fd1不同的,只是复制了一份fd1d的描述符表。所以两个fd对应的相同的文件指针,因此dup 和dup2其实只能接续读写)
我们关注文件共享时是关心文件读写是分别读写还是接续写
*************父进程创建的子进程退出后,父进程没有回收子进程的结束信息时,子进程就便成一个僵尸进程,因此档一个父进程调用fork函数创建一个子进程而不调用wait函数时,一个僵尸进程就诞生了。
***************当父进程在子进程之前结束运行,这时该子进程就成为孤儿进程,linux系统由init进程负责领养所有的孤儿进程