前言
苦逼本科生要考試,考試還奇難內(nèi)容齊多
這里我整理一下考試提綱
正好這也是對《unix環(huán)境高級編程》的前半部分的一個總結(jié)
就當(dāng)看著樂
還是lxd大佬流弊贴硫,都是他帶我的
正文
什么是操作系統(tǒng)疤坝?什么是UNIX操作系統(tǒng)槽驶?什么是Linux操作系統(tǒng)?它們之間的關(guān)系是怎樣的莱睁?
操作系統(tǒng)是管理和控制計算機(jī)硬件和軟件資源的計算機(jī)程序,是直接運行在“裸機(jī)”上的最基本的系統(tǒng)軟件芒澜。
UNIX是一個與1969年在AT&T的貝爾實驗室開發(fā)的多用戶多任務(wù)的分時的操作系統(tǒng)
Linux是一個基于POSIX和UNIX的多用戶缩赛、多任務(wù)、支持多線程的開源的由Linus開發(fā)的操作系統(tǒng)
Linux是基于UNIX而構(gòu)造的撰糠。
UNIX操作系統(tǒng)有哪些典型的分支酥馍?
Solaris,Linux阅酪,HP-UX旨袒,F(xiàn)reeBSD汁针,SunOS,MacOS
程序運行時砚尽,堆棧如何變化施无?什么是數(shù)據(jù)幀或活動記錄?bp和sp指針在函數(shù)運行過程中是如何變化的必孤?
新的棧中變量會在地址低的位置猾骡,新的堆中變量會在地址高的位置。
棧是向低地址延伸的敷搪,堆是向高地址延伸的兴想。
(這里的數(shù)據(jù)幀是不是棧幀啊……我google只查到計算機(jī)網(wǎng)絡(luò)相關(guān)的數(shù)據(jù)幀)
(具體看編譯原理)
過程活動記錄,又稱棧幀赡勘,棧幀包含了局部變量嫂便,函數(shù)試產(chǎn),臨時值等數(shù)據(jù)信息以及必要的控制信息闸与。
在函數(shù)調(diào)用過程中毙替,會講被調(diào)用者的過程活動記錄以堆棧的形式存儲
函數(shù)的調(diào)用過程中,bp會保存當(dāng)前棧幀的起始地址(保持不變)践樱,sp指示棧頂?shù)奈恢贸ЩkS著函數(shù)運行有出棧入棧的操作,sp的值會隨之發(fā)生變化拷邢。
每當(dāng)函數(shù)調(diào)用時袱院,會把被調(diào)用者棧幀中的bp壓棧,然后講當(dāng)前的sp賦給bp表示這是被調(diào)用者的棧幀起始地址解孙,然后再講參數(shù)通過bp放入(bp+4*n)的地址
函數(shù)調(diào)用
? [調(diào)用過程](javascript:void())涉及到計算機(jī)CPU內(nèi)部的一些概念坑填,最主要的有棧(stack)、棧幀(fram stack)弛姜、返回值(一般通過ax寄存器)脐瑰、基址寄存器(bp)、棧寄存器(sp)廷臼、指令指針寄存器(ip)等苍在。言簡意賅的說,每個函數(shù)在運行過程中荠商,在棧上都以棧幀的形式保存臨時變量寂恬,也就是中間結(jié)果。如果它還調(diào)用其他函數(shù)莱没,需要傳遞的參數(shù)也是通過棧幀來傳遞的(不同體系結(jié)構(gòu)可能不一樣)初肉。每個棧幀有開始和結(jié)束,bp寄存器保存當(dāng)前棧幀的起始位置(保持不變)饰躲,sp指示棧頂?shù)奈恢醚烙剑S著函數(shù)運行會有出棧臼隔、入棧操作,sp的值會隨之發(fā)生變化妄壶。ip始終指向下一個運行的匯編代碼的虛擬地址摔握。調(diào)用函數(shù)(caller)在調(diào)用被調(diào)函數(shù)(callee)之前,首先會把參數(shù)壓棧丁寄,然后運行call <function>指令氨淌,CPU就會把當(dāng)前過程的下一條指令的地址壓棧(這一步是CPU自動執(zhí)行的,匯編代碼看不出棧的變化)伊磺,以便調(diào)用返回時繼續(xù)執(zhí)行盛正;還會保存標(biāo)志位寄存器flag和段寄存器cs(視不同調(diào)用類型而定)。callee運行奢浑,首先會把caller棧幀的bp壓棧(返回時需要恢復(fù))蛮艰,然后將當(dāng)前的sp賦值給bp腋腮,表明這時的bp是callee的棧幀起始地址雀彼;然后取出caller傳進(jìn)來的參數(shù)(在caller棧幀中,通過bp寄存器為參考點獲取參數(shù)即寡,(bp+8),(bp+12)...)徊哑。這里可能會有點困惑的是(bp+0),(bp+4)的內(nèi)容是什么聪富?上面說到進(jìn)入callee后首先要做的就push %bp莺丑,此處的bp寄存器保存的是上一棧幀的起始位置。而進(jìn)入callee必須保存上一過程的返回地址墩蔓。這樣就清楚了(bp+0)的值是上一個過程的棧幀值梢莽,(bp+4)是callee返回后caller執(zhí)行的下一個指令地址。通過這樣的[函數(shù)調(diào)用規(guī)約](javascript:void())奸披,程序運行時的每次調(diào)用就能準(zhǔn)確無誤昏名。如果有返回值,一般以ax寄存器傳遞返回值阵面,那么在返回caller后轻局,需保存ax寄存器的值。
UNIX環(huán)境下編程共同遵循的規(guī)范有哪些样刷?“Least Surprise”是什么意思仑扑?
KISS(Keep It Simple, Stupid)
還有其他的?UNIX哲學(xué)置鼻?
Least Surprise 是減少不必要的創(chuàng)新镇饮,從而減少用戶的學(xué)習(xí)成本
什么是Shell?內(nèi)置變量$箕母、$*储藐、$@梅肤、$?、$#的具體含義是什么邑茄?
$$
指當(dāng)前shell進(jìn)程的pid
$*
指的是傳遞給腳本的所有參數(shù)
$@
也是把所有參數(shù)傳遞給腳本姨蝴,但是當(dāng)參數(shù)被雙引號包含的時候,$*
會把所有的參數(shù)作為一個整體肺缕,而$@
會將各個參數(shù)分開
$?
指的是上個命令的退出狀態(tài)左医,或函數(shù)返回值
$#
指的是傳遞給腳本或函數(shù)的參數(shù)個數(shù)
Shell特殊變量:Shell $0, $#, $*, $@, $?, $$和命令行參數(shù)
常用的Shell命令,如ls同木、cd浮梢、dd、pwd彤路、ps秕硝、cp、chown洲尊、chmod远豺、mkdir、size等的具體用法坞嘀。
ls (list)列出所有文件
cd (change directory)換工作目錄
dd (disk dump)指定大小拷貝文件
pwd (print working directory)打印工作目錄
ps (processes status) 顯示終端下所有進(jìn)程
cp (copy)復(fù)制
chown (change owner)改變文件的所有者
chmod (change mode )改變文件的權(quán)限模式
mkdir (make directory)
size 顯示目標(biāo)文件長度
什么是管道躯护?哪些文件參與了管道?在命令行下和通過編程如何實現(xiàn)管道丽涩?
管道是進(jìn)程間的通信的工具
stdin, stdout, stderr三個文件參與了管道
在命令行下棺滞,可以通過"|"實現(xiàn)管道。前一個進(jìn)程產(chǎn)生的輸入傳輸?shù)篮笠粋€進(jìn)程之中矢渊。
在linux c下继准,可以通過pipe去實現(xiàn)管道
/*
無名管道的生成
*/
#include<unistd.h>
int main()
{
int pipefd[2]; // pipefd[0]是輸入fd, pipefd[1]是輸出fd
pipe(pipefd);
}
常規(guī)文件和目錄文件的差別是什么?常規(guī)文件矮男、目錄文件移必、軟鏈接文件的長度如何計算?
目錄文件也是一種特殊的文件昂灵,里面存放的是父目錄節(jié)點和孩子文件避凝。
常規(guī)文件只要用戶擁有讀權(quán)限就可以讀,如果用戶擁有寫權(quán)限就可以寫眨补。
目錄文件的讀只需用戶擁有這個目錄的讀權(quán)限管削,但是寫時靠操作系統(tǒng)內(nèi)核寫的。
常規(guī)文件的長度根據(jù)其內(nèi)容計算撑螺。
目錄大小根據(jù)目錄文件對應(yīng)的inode的Block的大小含思。一般文件不多的情況下都是4096即4K的大小。而一般情況下都是4K的n倍,n取決于目錄下文件的數(shù)量
軟鏈接的文件長度就是目標(biāo)文件的文件名字符長度含潘,就比如一個指向AAA
的軟連接的文件大小是3饲做,因為AAA
有三個字符
怎樣移動文件?在命令行方式下和通過編程如何實現(xiàn)遏弱?
在命令行的方式下盆均,可以通過mv命令來移動文件
mv oldFile oneDir/newFile
在Linux C下貌似沒有直接移動文件的函數(shù),但是可以通過創(chuàng)建硬鏈接和刪除原有鏈接的方式實現(xiàn)
但是可以使用rename()
函數(shù)漱逸,取得同樣的效果
怎樣利用gcc編譯源文件泪姨?gcc的-o、-e饰抒、-static肮砾、-Wall等選項的具體含義是什么?怎樣使用袋坑?
gcc cFile.c
生成一個名為a.out的可執(zhí)行文件
-o可以指定生成文件的名字
gcc -o test cFile.c
之后生成名為test的可執(zhí)行文件
-E只激活預(yù)處理仗处,并不生成文件
需要將其重定向到一個輸出文件里面
gcc -E cFile.c > redirector.c
-static靜態(tài)編譯,生成的文件不依賴動態(tài)鏈接庫而使用靜態(tài)鏈接庫枣宫,可移植性高婆誓,缺點是生成的可執(zhí)行文件非常大
gcc -static cFile.c
gcc -e 設(shè)置程序的入口函數(shù)
//test.c
void fun()
{
printf("helloWorld");
}
gcc -e fun test.c
一般情況下加上-nostartfiles參數(shù),這個就避免了main的鏈接
-Wall在編譯過程中會顯示所有的warning信息
什么是動態(tài)鏈接庫镶柱?什么是靜態(tài)鏈接庫旷档?怎樣用靜態(tài)鏈接的方式編譯C程序模叙?
動態(tài)鏈接庫(dynamic link library, dll)是指可以c等編程語言在變編譯時候依賴的庫歇拆。在編譯過程中這些庫不會鏈接到可執(zhí)行文件中,所以文件大小比較小范咨,缺點是可移植性不強
靜態(tài)鏈接庫(.lib文件)是在c等編程語言在編譯的時候?qū)戽溄拥娇蓤?zhí)行文件中故觅,所以文件大小比較大,但是又較好的可移植性
gcc默認(rèn)使用動態(tài)鏈接地方式編譯渠啊,如果想使用靜態(tài)鏈接就需要用-static選項
什么是文件系統(tǒng)输吏?UNIX的文件系統(tǒng)有什么特點?有哪些具體的文件類型替蛉?
文件系統(tǒng)是操作系統(tǒng)在存儲設(shè)備上組織文件的方法和數(shù)據(jù)結(jié)構(gòu)贯溅。
UNIX的文件系統(tǒng)是依靠inode的vnode的霹娄。
在進(jìn)程表項中都維護(hù)一個文件表涨缚,文件表中有文件狀態(tài)標(biāo)志友存、當(dāng)前文件的偏移量和vnode指針蛋逾。vnode指針指向了一個vnode節(jié)點茸苇,其中包含了vnode節(jié)點信息和對inode的指針埃跷。
inode指向了磁盤上的文件墩崩。
磁盤上的文件至少對應(yīng)一個inode盯荤,當(dāng)一個文件的inode達(dá)到0時,文件被正式刪除镊折。
每個目錄的硬鏈接數(shù)至少有2個胯府,自己與父目錄。
具體的文件類型:
- 常規(guī)文件
- 目錄文件
- 字符特殊文件:對設(shè)備不帶緩沖的訪問
- 塊特殊文件:對設(shè)備帶緩沖的訪問
- FIFO:用于進(jìn)程間的通信
- 套接字:用于進(jìn)程間的網(wǎng)絡(luò)通信
- 軟鏈接
什么是文件的訪問權(quán)限恨胚?使用chmod命令怎樣改變訪問權(quán)限骂因?chmod 0777是什么意思?
訪問權(quán)限指的是文件是否可以被不同類型的人訪問的標(biāo)識符
chmod
在shell中是
chmod u+x g+w filename #user現(xiàn)在可以執(zhí)行赃泡,group現(xiàn)在可以寫入
chmod u=rwx g=rw o=r filename #對于filename來說侣签,user現(xiàn)在read write execute都被允許,group只被允許read和write急迂,other可以read
chmod 0777代表著對于user/group/others來說影所,都可以對filename讀寫執(zhí)行了
什么是文件操作是的偏移量(offset)?它的數(shù)據(jù)類型是什么僚碎?操作系統(tǒng)中文件的最大長度取決于什么猴娩?
偏移量指的是現(xiàn)在文件操作的指針指向的是文件的第幾個字節(jié)。
數(shù)據(jù)類型是offset_t
操作系統(tǒng)中文件的最大長度取決于文件自身的字節(jié)數(shù)和塊大小勺阐。#有點迷卷中,不回答
什么是管道?什么是文件重定向渊抽?dup()蟆豫、dup2()函數(shù)怎樣使用?
管道是進(jìn)程間的通信的工具
文件重定向是指將進(jìn)程的標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)輸入換成文件流
int dup(int oldd);
dup返回新文件描述符是當(dāng)前可用文件描述符中的最小值
int dup2(int fd, int fd2);
dup2可以用fd2指定新描述符的值懒闷,如果fd2已經(jīng)打開十减,則先將其關(guān)閉。
什么是文件的靜態(tài)屬性和動態(tài)屬性(文件描述符屬性)愤估?在文件描述符屬性中帮辟,哪些是由進(jìn)程維護(hù)的?哪些是由內(nèi)核維護(hù)的玩焰?
靜態(tài)屬性:由stat()函數(shù)顯示的文件屬性都是靜態(tài)屬性由驹。包括.... ls -l的結(jié)果都是
動態(tài)屬性:在打開文件之后知道的文件的屬性,就比如文件的offset
進(jìn)程維護(hù):FD_CLOEXEC (file descriptor close on exec() )(ps: 還是lxd大佬流弊昔园,都是他帶我)
什么是會話(Session)蔓榄、進(jìn)程組?它們之間有什么關(guān)系默刚?
進(jìn)程組是一個或多個進(jìn)程的集合
會話是一個或多個進(jìn)程組的集合甥郑。
關(guān)系:會話是一個或多個進(jìn)程組的集合。
父進(jìn)程和子進(jìn)程之間是什么關(guān)系羡棵?怎樣在父子進(jìn)程之間共享文件描述符壹若?
父進(jìn)程通過調(diào)用fork函數(shù)生成子進(jìn)程,并且通過waitpid的方式回收子進(jìn)程使其不成為僵尸進(jìn)程。在子進(jìn)程未通過調(diào)用exec執(zhí)行新的代碼的時候店展,父進(jìn)程與子進(jìn)程的所有信息完全相同养篓,包括文件表。
在子進(jìn)程創(chuàng)建之初就已經(jīng)共享文件描述符(因為父進(jìn)程與子進(jìn)程的文件表相同赂蕴。)只要在fork之前打開的文件柳弄,都可以被父子進(jìn)程共享。
在一個進(jìn)程中概说,文件描述符的增長規(guī)律是怎樣的碧注?例如,如果已經(jīng)有0糖赔、1萍丐、2、6這樣幾個文件描述符放典,那么用open()返回的下一個文件描述符是什么逝变?
是最小的未被使用的的非負(fù)整數(shù)。3
什么是process id奋构?父進(jìn)程和子進(jìn)程的pid之間有什么關(guān)系壳影?(通常子進(jìn)程的pid要大于父進(jìn)程的pid)
process id 即進(jìn)程id,是一個進(jìn)程獨有的編號弥臼;
父進(jìn)程總是會比子進(jìn)程先創(chuàng)建出來宴咧,故父親的pid<子進(jìn)程pid。
什么是C語言程序的入口函數(shù)径缅?在C Startup Routine(start.S)中接受的main函數(shù)原型是什么掺栅?
C語言程序的入口函數(shù)是main函數(shù)。C程序總是從main函數(shù)開始執(zhí)行芥驳。
在c語言編譯過程中柿冲,從_start
開始執(zhí)行。
而_start
會調(diào)用libc_start_main函數(shù)兆旬,libc_start_main這個函數(shù)的第一個參數(shù)就是指向一個
main函數(shù)的指針
main
函數(shù)的簽名為int main(int argc, char **argv, char** environ)
三個參數(shù)分別代表參數(shù)的個數(shù),參數(shù)和環(huán)境變量怎栽。
什么是系統(tǒng)調(diào)用丽猬?什么是C語言庫函數(shù)?它們之間有什么區(qū)別和聯(lián)系熏瞄?
系統(tǒng)調(diào)用:unix操作系統(tǒng)所提供的良好定義脚祟、數(shù)量有限、之間進(jìn)入內(nèi)核的入口點
C語言庫函數(shù):這里指的是程序員使用的通用庫函數(shù)强饮。雖然折現(xiàn)函數(shù)可能會調(diào)用一個或多個內(nèi)核的系統(tǒng)調(diào)用由桌,但是它們都不是內(nèi)核的入口點
聯(lián)系:它們都通過C函數(shù)的形式出現(xiàn)并且都為應(yīng)用程序提供服務(wù)
區(qū)別:
- 庫函數(shù)是可以靈活地被替換的,但是系統(tǒng)調(diào)用不是
- 兩者的職責(zé)和操作的層面不同。庫函數(shù)常在用戶層次管理上而系統(tǒng)調(diào)用在內(nèi)核層次上
什么是inode行您?里面存放什么信息铭乾?文件的文件名存放在哪里?
inode是索引節(jié)點娃循,是UNIX操作系統(tǒng)中包含文件系統(tǒng)重要信息的一種數(shù)據(jù)結(jié)構(gòu)炕檩。
里面存放了包括文件所有者,文件長度捌斧,文件在磁盤上的位置的指針等等信息笛质。
文件的文件名存放在目錄項中
C程序的內(nèi)存布局是怎樣的?從低地址到高地址依次存放哪些段捞蚂?
從低到高:代碼段妇押,初始化過的數(shù)據(jù),未初始化過的數(shù)據(jù)姓迅,堆舆吮,棧,命令行參數(shù)和環(huán)境變量
其中程序的靜態(tài)變量都放在代碼段中队贱。
在棧中色冀,后入的變量居于低地址,先入的變量居于高地址
怎樣利用fork()柱嫌、exec()锋恬、waitpid()來創(chuàng)建和控制進(jìn)程?
父進(jìn)程調(diào)用fork()编丘,之后程序中應(yīng)該有一個條件判斷判斷是否為子進(jìn)程与学,如果是,則子進(jìn)程調(diào)用exec嘉抓,并且會將if中其他代碼全部替換掉索守。之后,父進(jìn)程執(zhí)行waitpid抑片,回收子進(jìn)程卵佛,防止其變?yōu)榻┦M(jìn)程
什么是孤兒進(jìn)程、什么是僵尸進(jìn)程敞斋?它們有什么特點截汪?怎樣避免產(chǎn)生過多僵尸進(jìn)程?
孤兒進(jìn)程就是指父進(jìn)程早于子進(jìn)程結(jié)束植捎,從而沒有父進(jìn)程的子進(jìn)程
孤兒進(jìn)程會被1號進(jìn)程托管衙解,并且在結(jié)束的時候被回收
僵尸進(jìn)程就是指由于種種原因,父進(jìn)程遲遲不使用wait
和waitpid
回收的子進(jìn)程
僵尸進(jìn)程一直在進(jìn)程表中占有一個進(jìn)程表象焰枢,但并沒有占用任何資源(因為進(jìn)程結(jié)束的時候資源早已回收)
可以使用兩次fork的方法避免產(chǎn)生過多的僵尸進(jìn)程蚓峦。調(diào)用兩次fork然后直接殺死子進(jìn)程舌剂,留下孫子進(jìn)程被1號進(jìn)程托管,待其結(jié)束被1號進(jìn)程回收暑椰。
什么是前臺進(jìn)程霍转?什么是后臺進(jìn)程?一個會話有幾個前臺進(jìn)程組和幾個后臺進(jìn)程組干茉?
前臺進(jìn)程:用戶使用的有控制終端的進(jìn)程
后臺進(jìn)程:是運行在后臺的一種特殊進(jìn)程谴忧。但仍聯(lián)系控制終端并且周期性地執(zhí)行某種任務(wù)或者等待處理某些發(fā)生的事件。
attention: 后臺進(jìn)程和守護(hù)進(jìn)程并不是一個概念角虫。守護(hù)進(jìn)程完全獨立于控制終端而后臺進(jìn)程并沒有
在控制終端終止時沾谓,后臺進(jìn)程會隨著前臺進(jìn)程一起終止,但是守護(hù)進(jìn)程不會
守護(hù)進(jìn)程會常駐內(nèi)存戳鹅,防止關(guān)掉控制終端內(nèi)存消失
一個會話中包含一個前臺進(jìn)程組均驶,一個或多個后臺進(jìn)程組。
C程序如何退出并返回操作系統(tǒng)枫虏?exit()函數(shù)和_exit()/_Exit()函數(shù)的差別在哪里妇穴?
進(jìn)程的終止方式有 8 種,其中 5 種為正常終止
- 從 main 返回。
- 調(diào)用 exit隶债。
- 調(diào)用_exit 或_Exit腾它。
- 最后一個線程從其啟動例程返回。
- 最后一個線程調(diào)用pthread_exit死讹。
另外三種為異常終止方式,它們是
- 調(diào)用 abort瞒滴。
- 接到一個信號并終止。
- 最后一個線程對取消請求做出響應(yīng)赞警。
void exit(int status)
void _Exit(int status)
void _exit(int status)
第一個是C語言的庫函數(shù)
第二個是系統(tǒng)調(diào)用的POSIX標(biāo)準(zhǔn)的函數(shù)
第三個系統(tǒng)調(diào)用的ISO標(biāo)準(zhǔn)的函數(shù)
系統(tǒng)調(diào)用的特點是系統(tǒng)調(diào)用不會調(diào)用退出處理函數(shù)妓忍,但是C語言的庫函數(shù)會
//
// Created by kardel on 5/28/18.
//
#include<unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>
void print_syscall()
{
printf("HelloWorld");
_Exit(0);
}
void print_clib()
{
printf("HelloWorld");
exit(0);
}
int main()
{
printf("in clib:\n");
print_clib();
// printf("in syscall:\n");
// print_syscall();
}
這樣的結(jié)果是
in clib:
HelloWorld
如果注釋掉上面兩行,結(jié)果是
in syscall:
因為printf的打印在結(jié)束調(diào)用函數(shù)中愧旦,但是_Exit()直接退出世剖,就不存在結(jié)束調(diào)用
exec函數(shù)族包含哪些具體的函數(shù)?其中execve是系統(tǒng)調(diào)用笤虫,其它都是普通函數(shù)旁瘫。
函數(shù)簽名 | 解釋 |
---|---|
int execl(const char * pathname, const char * arg0, .../*, NULL*/); |
根據(jù)pathname所代表的文件路徑通過給定的參數(shù)執(zhí)行進(jìn)程。注意arg0應(yīng)該是程序本身 |
int execle(const char * pathname, const char * arg0, ..., /*, NULL, char * const envp[]*/); |
根據(jù)pathname所代表的文件路徑通過給定的參數(shù)執(zhí)行進(jìn)程耕皮。最后一個參數(shù)是環(huán)境變量數(shù)組境蜕。注意arg0是程序本身 |
int execlp(const char * pathname, const char * arg0, ... /*, NULL*/); |
在環(huán)境變量中根據(jù)pathname找文件并且通過給定參數(shù)執(zhí)行進(jìn)程。注意arg0應(yīng)該是程序本身 |
int execv(const char * pathname, char * const argv[]); |
根據(jù)pathname所代表的文件路徑通過給定的參數(shù)的數(shù)組執(zhí)行進(jìn)程凌停。注意數(shù)組第一個元素應(yīng)該是程序本身 |
int execvp(const char * pathname, const char * arg0); |
在環(huán)境變量中根據(jù)pathname找文件并且通過給定參數(shù)的數(shù)組執(zhí)行進(jìn)程。注意數(shù)組第一個元素應(yīng)該是程序本身 |
int fexecve(int fd, char * const argv[], char * const envp[]); |
在環(huán)境變量中根據(jù)file descriptor找文件并且通過給定參數(shù)的數(shù)組執(zhí)行進(jìn)程售滤。注意數(shù)組第一個元素應(yīng)該是程序本身罚拟。最后一個參數(shù)是環(huán)境變量數(shù)組 |
int execve(const char * pathname, char * const argv[], char * const envp[]); |
真正的系統(tǒng)調(diào)用台诗。根據(jù)pathname所代表的文件路徑通過給定的參數(shù)的數(shù)組執(zhí)行進(jìn)程。注意數(shù)組第一個元素應(yīng)該是程序本身赐俗。最后一個參數(shù)是環(huán)境變量數(shù) |
*什么是信號拉队?SIGINT、SIGSTOP阻逮、SIGHUP粱快、SIGALARM、SIGQUIT等信號是如何產(chǎn)生的叔扼?缺省的處理動作是什么事哭?
信號是異步事件通知進(jìn)程的一種方式。
信號處理函數(shù)靠內(nèi)核進(jìn)行
因為這個已經(jīng)脫離了用戶自定義的范圍瓜富,轉(zhuǎn)而變成了操作系統(tǒng)的范圍
信號產(chǎn)生的方法:
用戶通過按某些終端鍵可以引發(fā)終端產(chǎn)生信號
硬件異常產(chǎn)生信號
用戶可以通過kill函數(shù)講任意信號發(fā)給另一個進(jìn)程或進(jìn)程組鳍咱。接收信號的進(jìn)程和發(fā)送信號的進(jìn)程的所有者必須相同∮敫蹋或者發(fā)送信號進(jìn)程的所有者是超級用戶
用戶通過kill命令講信號發(fā)送給其他進(jìn)程
-
當(dāng)檢測到某種軟件條件已經(jīng)發(fā)生并應(yīng)該將其通知有關(guān)進(jìn)程時也產(chǎn)生信號谤辜。
這四個缺省的處理動作都是終止。
什么是硬鏈接和軟鏈接(符號鏈接)价捧?讀取軟連接的函數(shù)是什么丑念?(readlink)
硬鏈接:通過 i 節(jié)點鏈接使多個目錄項指向同一個文件的這種鏈接類型。
符號鏈接:對一個文件的間接指針结蟋,一般用于將一個文件或整個目錄結(jié)構(gòu)移到文件系統(tǒng)中的另一個位置脯倚。
ssize_t readlink(const char * restrict pathname, char * restrict buf, size_t bufsize)
可以打開軟連接并且讀該軟鏈接中的名字
函數(shù)link()和unlink()的作用是什么?什么時候文件占用的磁盤空間才會真正被釋放掉椎眯?(兩個條件)
int link(const char * existingpath, const char * newpath);
根據(jù)existingpath創(chuàng)造一個路徑為newpath的硬鏈接挠将。
int unlink(const char * pathname);
刪除一個硬鏈接
當(dāng):
沒有硬鏈接指向文件
-
進(jìn)程關(guān)閉該文件或進(jìn)程終止
時,在磁盤空間內(nèi)的文件才會被釋放掉
什么是可重入函數(shù)编整?怎樣判斷一個函數(shù)是不是可重入函數(shù)舔稀?
可重入函數(shù)是在信號處理程序中保證調(diào)用安全的函數(shù)。
不是可重入函數(shù)的幾個特點:
- 使用靜態(tài)數(shù)據(jù)結(jié)構(gòu)
- 他們調(diào)用
malloc
或free
- 它們是標(biāo)準(zhǔn)I/O函數(shù)
什么是帶緩沖的輸出和不帶緩沖的輸出掌测?當(dāng)父進(jìn)程的輸出緩沖區(qū)還未清空時内贮,調(diào)用fork創(chuàng)建子進(jìn)程,會出現(xiàn)什么情況汞斧?
不帶緩沖的輸出是在調(diào)用時直接將內(nèi)容輸出到標(biāo)準(zhǔn)輸出端/文件夜郁,而不是經(jīng)過緩沖區(qū)。比如printf
函數(shù)
帶緩沖區(qū)的輸出實在調(diào)用的時候?qū)?nèi)容緩沖在緩沖區(qū)粘勒,等到程序結(jié)束了再一并寫入輸入端/文件竞端,比如fprintf
函數(shù)
會打印兩次相同的內(nèi)容
//
// Created by kardel on 5/28/18.
//
#include<unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
FILE *fd = fopen("test.txt", "a");
char * buffer = "HELLO\n";
fwrite(buffer, 6, 1, fd);
int pid = fork();
//我懶得寫waitpid,僵尸就僵尸吧
}
可以看見在test.txt中的內(nèi)容是
HELLO
HELLO
編程的題目在這次考試中占很大的比重。一共有兩道編程的題目庙睡。第一道跟文件操作相關(guān)事富,要求詳細(xì)掌握的用法包括:能用open,read,write,close等函數(shù)來操縱文件技俐;能利用lseek來形成文件中的“空洞”;能動態(tài)申請和釋放空間等统台。
注意點: lseek
形成文件空洞之后要立即寫入起碼一個字節(jié)雕擂,否則空洞無效。
幾個文件狀態(tài):
文件狀態(tài)標(biāo)志 | 說明 |
---|---|
O_RDONLY | 只讀打開 |
O_WRONLY | 只寫打開 |
O_RDWR | 讀寫打開 |
O_EXEC | 只執(zhí)行打開 |
O_SEARCH | 只搜索打開目錄 |
O_APPEND | 只添加新內(nèi)容 |
O_NONBLOCK | 非堵塞 |
O_SYNC | 等待寫完成(數(shù)據(jù)與屬性) |
O_DSYNC | 等待寫完成(僅數(shù)據(jù)) |
O_RSYNC | 同時讀寫 |
O_FSYNC | 等待寫完成 |
O_ASYNC | 異步I/O |
O_TRUNC | 截斷文件贱勃,重頭再來 |
O_CREAT | 創(chuàng)造 |
幾個簽名:
int open(const char * pathname, int flags, mode_t mode);
返回文件描述符
例如
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
int main()
{
int fd;
fd=open("abc",O_CREAT,0777);
printf("fd=%d\n",fd);
return 0;
}
ssize_t write(int fd, const void * buf, size_t count)
將存在buf中的寫入fd指定的文件中井赌,寫入count個字節(jié),返回寫入的字節(jié)數(shù)贵扰。如果返回-1則出錯
ssize_t read(int fd, void * buf, size_t count)
將fd指定的文件中的內(nèi)容讀到buf中仇穗,讀count個字節(jié),返回讀出的字節(jié)數(shù)拔鹰。如果返回-1則讀出錯
第二道編程的題目跟進(jìn)程和信號相關(guān)仪缸。要求詳細(xì)掌握的用法包括:能用pause函數(shù)阻塞進(jìn)程;能用signal設(shè)置信號處理函數(shù)列肢;能向特定進(jìn)程發(fā)送信號恰画;能用rename移動文件;能遍歷目錄瓷马;能用S_ISREG宏辨別文件類型等等拴还。切記對最后兩道編程的大題要提前做好準(zhǔn)備
int pause()
使調(diào)用進(jìn)程睡眠,直到接收到信號欧聘。pause
返回-1片林,errno
設(shè)置為EINTR
void (*signal(int signo, void (*func)(int)))(int)
第一個參數(shù)使調(diào)整的信號,第二個參數(shù)是一個函數(shù)怀骤,這個函數(shù)的參數(shù)是信號
打開目錄通過
DIR * opendir(const char* name);
打開目錄通過
struct dirent * readdir(DIR *dir);
返回一個struct dirent *類型
struct dirent{
ino_t dino; //inode number
off_t d_off; //offset to the next dirent
unsigned short d_reclen //length of this record
unsigned char d_type; //type of file
char d_name[256]; //name of the file
關(guān)閉文件夾
int closedir(DIR * dir)
注意:遍歷目錄的時候要把上一級和目錄以及隱藏文件去掉费封,避免死循環(huán)遍歷
用
if(strncmp(file->d_name, ".", 1) == 0)
{
continue;
}
整體大概是
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
len = 0;
int trave_dir(char *path)
{
DIR *d; //聲明一個句柄
struct dirent *file; //readdir函數(shù)的返回值就存放在這個結(jié)構(gòu)體中
struct stat sb;
if (!(d = opendir(path)))
{
printf("error opendir %s!!! \n", path);
return -1;
}
while ((file = readdir(d)) != NULL)
{
stat(file->d_name, &sb);
if(S_ISREG(sb.st_mode))
printf("yes, this is a regular file: ");
printf("%s \n", file->d_name);
}
closedir(d);
return 0;
}
int main()
{
trave_dir(".");
}
在我的cmake-build-debug文件夾下它ls的結(jié)果是
ls -al
drwxrwxr-x 3 kardel kardel 4096 Jun 15 20:04 .
drwxrwxr-x 4 kardel kardel 4096 Jun 15 20:04 ..
-rw-rw-r-- 1 kardel kardel 44891 May 28 05:58 CMakeCache.txt
drwxrwxr-x 5 kardel kardel 4096 Jun 15 20:04 CMakeFiles
-rw-rw-r-- 1 kardel kardel 1539 May 28 05:58 cmake_install.cmake
-rw-rw-r-- 1 kardel kardel 5149 Jun 15 19:49 Makefile
-rw-rw-r-- 1 kardel kardel 12 Jun 15 19:24 test.txt
-rwxrwxr-x 1 kardel kardel 12344 Jun 15 20:04 untitled
-rw-rw-r-- 1 kardel kardel 5536 Jun 15 19:49 untitled.cbp
我的程序輸出是
yes, this is a regular file: Makefile
yes, this is a regular file: untitled.cbp
CMakeFiles
..
yes, this is a regular file: CMakeCache.txt
yes, this is a regular file: untitled
yes, this is a regular file: test.txt
yes, this is a regular file: cmake_install.cmake
.
rename移動文件
int rename(const char * oldpath, const char * newpath);
如果出錯,返回-1
宏 | 描述 |
---|---|
S_ISLNK | 是否為一個鏈接 |
S_ISREG | 是否為一個常規(guī)文件 |
S_ISDIR | 是否為一個目錄 |
S_ISCHR | 是否為一個字符串特殊文件 |
S_ISBLK | 是否為一個塊特殊文件 |
S_ISFIFO | 是否為FIFO文件 |
S_ISSOCK | 是否為一個socket文件 |
這些都可以通過
int stat(const char * restrict pathname, struct stat * restrict buf);
int fstat(int fd, struct stat * buf);
所得到的stat結(jié)構(gòu)體中的st_mode
得到蒋伦。他的類型是mode_t
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
struct stat buf;
int result = stat("../test.c", &buf);
if(result == 0)
{
if(S_ISREG(buf.st_mode))
{
printf("yes, it is a regular file");
}
else
{
printf("this is not a reg file!");
}
}
else{
printf("read error");
}
}
結(jié)果
yes, it is a regular file