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進程負責領養所有的孤兒進程