最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

③【linux系統(tǒng)編程】李慧芹老師嵌入式Linux

2022-07-05 22:24 作者:獄雷Guru  | 我要投稿

linux_c系統(tǒng)開發(fā)學(xué)習(xí)筆記


day1

知識點匯總

要求:

1.學(xué)習(xí)的時候棄用root用戶

原因:root 和 普通用戶 區(qū)別很大

用普通用戶 和工作的時候更加相似、往往沒有權(quán)限,能學(xué)習(xí)到更多的東西。

2.重構(gòu)之前寫的代碼

用新學(xué)到的機制來解決舊的問題

老師會提醒哪里可以重構(gòu)、提升代碼量


標(biāo)準IO

I/O 是一切實現(xiàn)的基礎(chǔ)

沒有io就保存不了數(shù)據(jù)

分為 stdio sysio 即標(biāo)準IO和系統(tǒng)調(diào)用IO

如何區(qū)分?

系統(tǒng)調(diào)用io是系統(tǒng)內(nèi)核提供的,沒有統(tǒng)一的接口

所以需要標(biāo)準化,就有了標(biāo)準io

解放了程序員

比如printf 不用考慮環(huán)境和編譯器

所以優(yōu)先使用標(biāo)準io 移植性好 合并系統(tǒng)調(diào)用

加速讀寫(buffer cache)

標(biāo)準io:

例如fopen分別依賴open和openfile

apue第五章


標(biāo)準IO FILE類型

結(jié)構(gòu)體,有什么類型?

拿來主義,先知道用法,


man操作

多看man手冊




不能用指針去改常量,雖然有可能得到xbc

取決于編譯器會把它放在哪兒

errno error number 是個全局變量 出錯會將其值設(shè)置 如果不及時輸出就會被其他error覆蓋

gcc -E 編譯預(yù)處理指令

私有化數(shù)據(jù)? error不再是一個整型而是一個宏

制造打開失敗,用只讀的方式打開一個不存在的文件!


eof 指向的是文件最后一個有效字符的下一個位置

a+打開,讀的話在最前面,寫的話在最后面!

文本流、二進制流

b 是對Windows系統(tǒng)起作用

有可能移植的時候考慮加不加b(以二進制進行操作)

man 給出的頭文件有幾個就要包幾個

不能省略


沒包頭文件=編譯器看不見函數(shù)原型

gcc會把所有的返回值視為整型

能夠吧errno 轉(zhuǎn)換為 errno msg的函數(shù):

perror (char*)

輸出的內(nèi)容+ 錯誤信息(根據(jù)當(dāng)前的errno輸出錯誤信息)

strerror(int errnum)

在<string.h> 里面


提問:fopen打開文件,返回的指針?biāo)赶虻哪菈K內(nèi)存是屬于 棧?靜態(tài)區(qū)?還是堆?

我覺得是棧 但是不對,因為如果是棧上的內(nèi)存,函數(shù)結(jié)束后就會被釋放,返回了局部變量的地址!

靜態(tài)區(qū)也不對,雖然確實可以返回,但是用static只能有一塊,每次都會被覆蓋。


localtime 里面的指針放在靜態(tài)區(qū)

從fclose也可看出,在動態(tài)申請的內(nèi)存中能釋放(逆操作 可以判定是在動態(tài)申請)

沒有逆操作,則不一定在堆上


是資源有上限

一個進程能打開多少文件?

一個進程首先需要打開三個流

strin strout strerr

shell也打開了(應(yīng)該)輸出重定向 輸入重定向

ulimit -a 查看 open files 限制的個數(shù)

創(chuàng)建文件的時候沒有指定文件的權(quán)限!

如何指定?0666按位與 ~umask

~是取反 0開頭是八進制數(shù)

可以用來限制進程創(chuàng)建的文件權(quán)限


遇到函數(shù)返回了指針

要下意識的判斷 該指針指向靜態(tài)區(qū)、堆還是棧?


day2 2022年7月6日

fgetc fputc 操作字符輸入輸出

getchar 相當(dāng)于getc(stdin)

getc相當(dāng)于fgetc

int getc(FILE *stream);

返回的int是轉(zhuǎn)換過的

fgetc 和 getc 一模一樣?不對

fgetc是函數(shù) getc是宏

函數(shù)和宏的區(qū)別:

宏只占用編譯的時間,不占用調(diào)用的時間,函數(shù)則相反

linux內(nèi)核中用宏是為了節(jié)約時間

日常應(yīng)用級開發(fā)還是多用函數(shù)+inline

putchar (c) = putc(c,stdout)

putc 是宏, fputc是函數(shù)

小作業(yè):寫一個mycp 要求:復(fù)制出來的dest文件要跟src文件一模一樣。


寫程序的建議:

先寫幾個常用的頭文件stdio.h stdlib.h

文件關(guān)閉順序:

最好首先關(guān)閉依賴別人的對象

然后關(guān)閉被依賴的對象

只要用到命令行,就要判斷命令行的參數(shù)(相當(dāng)于寫注釋)并給出提示信息

內(nèi)存泄露:打開第一個文件成功,打開第二個文件失敗了

此時第一個文件還沒有關(guān)閉。

現(xiàn)在允許這種情況發(fā)生,以后會用到鉤子函數(shù)(?沒聽清)

可以把一旦出錯就運行的函數(shù)放在一起執(zhí)行

gets(char *s)

gets 很危險,不要用,因為s可能會溢出


推薦用

fgets (char *s,int size,F(xiàn)ILE *stream)

fgets 正常結(jié)束的情況:讀到size-1個字節(jié) (最后給s末位一個\0)和 讀到一個'\n'。

例如:用fgets(buffer,5,fp)讀取 abcd

需要讀兩次 第一次讀 abcd'\0' 第二次讀'\n''\0'

fgets出錯時,返回一個空指針


fputs(buffer,fp);將buffer的內(nèi)容輸出到指定流中


size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream)

從stream中讀取 size * nmemb 大小的內(nèi)容到ptr指定的地方

size_t fwrite(const void *ptr, size_t size,size_t nmemb,FILE *stream)

從ptr指向的空間中讀取size*nmemb大小的內(nèi)容到stream中

問題:

1.錯位就全錯

2.返回值是成功讀到或者寫的對象個數(shù),不一定是字符的個數(shù)(即nmem)

可以當(dāng)做fgetc來使用


不能小瞧io操作,因為不熟悉io會導(dǎo)致后面的內(nèi)容難以理解


printf scanf

最好用fprintf,輸出重定向,比較有擴展性

sprintf 重定向到某一個字符串,比較像atoi的逆操作,但是沒有一個函數(shù)叫itoa

因為sprintf沒有指定緩沖區(qū)的大小,加了一個參數(shù),就有了snprintf,但是依舊沒有解決問題(最大字節(jié)數(shù)為size-1),因為后面的參數(shù)還是有可能造成緩沖區(qū)溢出。(fgets一樣有問題,不一定每次都能取滿)

scanf:從stdin以format格式取數(shù)據(jù),一個一個放到...里的參數(shù)去

fsancf 和 sscanf 都是重定向

sscanf:解析一個字符串把它里面的內(nèi)容按照format格式轉(zhuǎn)到...指定的位置

format里面最好不寫%s ?。。。ㄉ髦厥褂茫?/p>

因為你無法預(yù)測讀取的內(nèi)容有多長(可能溢出)這是scanf最大的缺陷之一

ftell 返回類型為long 很丑陋

因為不可能有文件指針有負數(shù)

但是為了遷就fseek(offset的參數(shù)類型long)

也就是說fseek和ftell在文件超過2g會失效

當(dāng)時一張軟盤16M 。。。所以。。


于是fseeko ftello 的參數(shù)變成了off_t(offset type)自己也可以使用這種技巧

off_t的大小一般來說是32位,但也不一定

這時可以利用宏可重復(fù)定義的特性,自己定義一下

#define _FILE_OFFSET_BITS 64

就可以吧off_t 轉(zhuǎn)換為64位的類型

gcc指令中也可以定義,makefile 也可以定義

CFLAGS+=-D_FILE_OFFSET_BITS=64

man手冊

CONFORMING TO 當(dāng)前函數(shù)所遵循的協(xié)議或標(biāo)準


可以看到fseeko是一個方言(不遵循c86或者c99 而是 posix)

而fseek是

那么當(dāng)文件比較大,而又要求移植性比較好,就得另辟蹊徑了。

fseek(FILE *fp,long offset,int whence) whence是起始位置,有SEEK_SET ,SEEK_CUR SEKK

rewind封裝了fseek

相當(dāng)于fseek(FILE *fp,0L,SEEK_SET);


fseek的妙用:產(chǎn)生空洞文件

例子:在使用迅雷等P2P下載的時候,下載的文件的大小不是從零開始的,而是一開始經(jīng)過了像fseek這樣的函數(shù),創(chuàng)建了一個大小與下載完成后的文件一樣的空洞文件,然后把該文件分塊,使用多線程或者多進程異步下載!

fflush()不刷新可能有意外發(fā)生

例子:

這樣無法打印出Before while()


標(biāo)準輸出是行緩沖模式,加上\n或者fflush才能輸出

fflush不帶參數(shù)時會刷新所有打開的流的緩沖區(qū),帶參數(shù)則刷新指定的流


緩沖區(qū)的作用:

修改緩沖區(qū) setvbuf


little trick:

在vim的命令行模式下

shift+k可以直接跳到man手冊上(coooool !)


問題:如何提取出完整的一行?

無論其大小

兩個選項

1.使用動態(tài)內(nèi)存來解決

2.getline

man getline

getline使用之前 需要宏定義一個_GNU_SOURCE

為什么要定義?為什么宏定義沒有替換的值?

經(jīng)過google發(fā)現(xiàn),_GNU_SOURCE相當(dāng)于一個開關(guān),用來讓用戶配置編譯環(huán)境的頭文件,這個宏可以讓用戶打開所有feature.

/* If _GNU_SOURCE was defined by the user, turn on all the other features.?*/

#ifdef _GNU_SOURCE

# undef?_ISOC99_SOURCE

# define _ISOC99_SOURCE?1

# undef?_POSIX_SOURCE

# define _POSIX_SOURCE?1

# undef?_POSIX_C_SOURCE

# define _POSIX_C_SOURCE?200112L

# undef?_XOPEN_SOURCE

# define _XOPEN_SOURCE?600

# undef?_XOPEN_SOURCE_EXTENDED

# define _XOPEN_SOURCE_EXTENDED?1

# undef?_LARGEFILE64_SOURCE

# define _LARGEFILE64_SOURCE?1

# undef?_BSD_SOURCE

# define _BSD_SOURCE?1

# undef?_SVID_SOURCE

# define _SVID_SOURCE?1

# undef?_ATFILE_SOURCE

# define _ATFILE_SOURCE?1

#endif


最好寫到makefile 當(dāng)中

練習(xí):自己封裝一個getline,實現(xiàn)讀一行


臨時文件

char* tmpnam(char *s)給一個字符地址,根據(jù)其中的內(nèi)容返回一個臨時文件名

在并發(fā)執(zhí)行的時候容易出錯,因為獲取文件名和創(chuàng)建文件不是一氣呵成的


FILE *tmpfile(void)

可以產(chǎn)生匿名文件,沒有名字就不會沖突(w+b方式打開)


一個文件,如果沒有任何的硬鏈接指向他,而當(dāng)前他的打開文件計數(shù)已經(jīng)成為零值,那么這個文件就會被銷毀。

所以如果fclose匿名文件的指針,那么該文件就被釋放了(如果沒有釋放且是守護進程就發(fā)生了泄漏)

還有其他方法創(chuàng)建臨時文件


day3 系統(tǒng)調(diào)用io

文件描述符在文件io中貫穿始終(fd)

上一個標(biāo)準io是FILE 指針


什么是文件描述符?

有哪些操作?

系統(tǒng)io的操作是支持標(biāo)準io的

fopen ->open等

本章知識點匯總


inode:文件的唯一標(biāo)識

文件描述符優(yōu)先使用當(dāng)前空閑的最小的整型值

(能夠復(fù)用之前用過的下標(biāo))


文件描述符的產(chǎn)生:

調(diào)用open函數(shù)

open函數(shù)需要包含以上三個文件

這里給出了兩種不同參數(shù)列表的open

提問:是用函數(shù)重載實現(xiàn)的?還是可變參數(shù)列表實現(xiàn)的?

應(yīng)該是可變參數(shù)列表,首先c語言中不能實現(xiàn)函數(shù)重載。若在C++環(huán)境中提問,則可以隨便傳幾個參數(shù),看他報錯的類型是參數(shù)類型error還是警告。


參數(shù)flags 是權(quán)限信息,由位圖實現(xiàn)。

他必須包含O_RDONLY O_WRONLY O_RDWR中的一個


更多的選項例如

文件的創(chuàng)建選項(creation flags)

文件的狀態(tài)選項(status flags)

可以通過按位或來進行選擇

O_CREAT,有則清空無則創(chuàng)建

O_TRUNC,截斷或者截短(truncate)

。。。有很多記不過來了


open返回值:成功返回fd失敗返回-1


day4


練習(xí):用系統(tǒng)io實現(xiàn)cp命令(重點,每次write不一定會全部寫入到fd中,要檢查寫入的個數(shù)和buffer的長度是否一致,不一致需要重復(fù)寫入)

為什么 第一個O_WRONLY和O_CREAT或運算了而后面的O_TRUNC是另外的參數(shù)?

應(yīng)該是寫錯了


文件IO和標(biāo)準IO的區(qū)別

標(biāo)準io是有緩沖的,吞吐量比較大(緩沖機制合并了系統(tǒng)調(diào)用)

文件io是實時的,響應(yīng)速度快。

如何使一個程序變快?

要區(qū)分是響應(yīng)速度還是吞吐量


標(biāo)準io和文件io不能混用??!

fileno可以轉(zhuǎn)換FILE* fp到 fd

fdopen可以把fd轉(zhuǎn)換為FILE *fp

為什么不能混用?至少pos不一樣!因為緩沖區(qū)會造成影響,fp的pos移動了,但是fd可能還沒來得及改動pos。反過來也是一樣,從fd中讀取一個cache塊大小,一下子讀出1024,但是fp中的pos可能才用到1個,并沒有加到1024

strace 跟蹤可執(zhí)行文件的系統(tǒng)調(diào)用


io效率問題

問題:bufsize的大小有何影響?

time命令 測試程序運行時間

練習(xí),把之前寫的cp的bufsize從128一直到16M測試他的時間,觀察在哪個點效率最高

不一定16M,直到段錯誤


可以看到,我用 truncate -s 2G test 命令創(chuàng)建了一個大小為2G的文件。



嘗試將其復(fù)制

用時20.739秒 此時的BUFSIZE為128

將BUFSIZE改為1024之后再次復(fù)制

用時減少到了4.228s??!

有沒有可能再減少一點呢?

我改成了8K的緩沖

2.56s! 依舊可以加速程序運行


128K: (和8K速度幾乎一樣)



似乎從8K~1M都差不多

16M會比較慢

區(qū)間應(yīng)該在8K到128K

32K

對于2G大小的文件

緩沖區(qū)大概設(shè)置為32k比較合適

這個文件緩沖比的大小為2^8

不知道這個結(jié)論有沒有普遍性?

后面發(fā)現(xiàn)沒有。。。(艸)

因為最佳效率在緩沖區(qū)為block的整數(shù)倍才會發(fā)生

可以用

stat / | grep "IO Block"

來查看當(dāng)前block的大小,我這邊服務(wù)器的block size為4K,這就是為什么在8K的時候效率會上升,且128K與8K差不多。(因為都是4K的整數(shù)倍?。?/p>


文件共享:

面試題:寫程序刪除一個文件的第十行

普通思路:打開文件一次,先找第11行,復(fù)制到第十行,像數(shù)組一樣依次覆蓋直到文件結(jié)束

這樣一次循環(huán)需要四次系統(tǒng)調(diào)用:seek


進階思路:打開文件兩次,一個只讀一個寫,

減少系統(tǒng)調(diào)用的次數(shù)

可以選用兩個進程還是兩個線程來進行這樣的操作

truncate/ftruncate函數(shù)截斷文件

作業(yè):實現(xiàn)上述功能


程序中的重定向:dup和dup2

duplicate 重復(fù),復(fù)制

int dup(oldfd)


close(1)和dup(fd)不是一個原子操作

也就是說,close1之后有可能其他人把1占用了

dup 的fd有可能不生成在1這個位置上,文件重定向就失敗了。

這里需要用到dup2這個原子操作

int dup2(oldfd , newfd)


dup2 (fd,1);dup2把第一個oldfd的描述符復(fù)制到第二個上,如果第二個被占用了,則會被關(guān)閉后復(fù)制。

老師寫的程序依然不對!

因為不能默認一個進程打開了012

而且有一個原則:不要以為自己在寫main函數(shù)

你總會與別人共同工作,在你修改了標(biāo)準流之后應(yīng)該還原回去。


day5


同步:

sync 同步內(nèi)核層面的buf和cache

解除設(shè)備掛載的時候,需要同步一下


fsync同步一個文件的buf和cache

fdatasync 只刷新數(shù)據(jù)不刷新亞數(shù)據(jù)(比如說文件的修改時間,文件的屬性)


fcntl(int fd,int cmd,...) :管理文件描述符

cmd可以選:F_DUPFD 。。。

cmd不同,返回值不同

管家級別的函數(shù)

dup和dup2封裝了fcntl


ioctl:設(shè)備相關(guān)的管家

一切皆文件好不好?

簡化了絕大數(shù)的操作,但是有些設(shè)備不僅僅是讀寫,損害了一小部分的利益


ioctl_list 居多,古董級別


/dev/fd/ 當(dāng)前運行進程的文件描述符目錄,是虛目錄。


文件系統(tǒng)


一、目錄和文件


獲取文件屬性:實現(xiàn)一個myls,盡力去模仿ls

問題:為什么有了短格式的選項還要有長格式?

因為短格式只能使用一次,有可能沖突

格式這類運維考的多


例如創(chuàng)建一個 文件名為-a的文件

兩種方法, -- (終止命令選項)或者指定路徑

myls可做選項 a i n l (uid gid)

不要求上色

這兩個文件可以找到uid和gid對應(yīng)的username和groupname,從而實現(xiàn)-n 和 -l


stat系統(tǒng)調(diào)用

fstat lstat (link stat)

獲取文件的屬性信息,填入buf中


復(fù)習(xí):FILE*和fd互相轉(zhuǎn)換的函數(shù)

FILE *fdopen(int fd, const char *mode);


int fileno(FILE *stream);


函數(shù)原型

tags工具:vim -t查看類型的詳情

off_t的位數(shù)是16?32?64?

不知道,所以不能直接用int代替

使用makefile 進行宏的重定義

例如

文件占的磁盤空間 blocksize*block數(shù)

并不等于文件的字節(jié)數(shù)

這里5G大小的文件只占用磁盤4K!


空洞文件:

cp支持空洞文件拷貝

cp拷貝的時候會檢查緩沖區(qū),如果全是空則記錄長度


文件類型 dcb-lsp

文件類型:

-:普通文件 (regular file)

d:目錄文件(directory)

b:塊設(shè)備文件 (block device)

c:字符設(shè)備文件 (character)

l:符號鏈接文件(symbolic link file)

p:命名管道文件(named pipe)

s:套接字文件(socket)

文件屬性的確定: 0666 & ~umask

umask為了防止產(chǎn)生權(quán)限過松的文件

文件權(quán)限的更改 chmod


粘住位 (t位?)

是給一個可執(zhí)行文件設(shè)計的,加速其再次裝載

現(xiàn)在因為有cache 所以一般給目錄設(shè)置

比如tmp目錄


文件系統(tǒng):

FAT和UFS 不開源和開源

FAT :靜態(tài)單鏈表,

輕量級,目前U盤還在用,并不難,相當(dāng)于本科學(xué)期期末作業(yè)







二、系統(tǒng)數(shù)據(jù)文件和信息

三、進程環(huán)境








③【linux系統(tǒng)編程】李慧芹老師嵌入式Linux的評論 (共 條)

分享到微博請遵守國家法律
通州市| 秭归县| 常山县| 阳西县| 琼结县| 庆安县| 广州市| 营山县| 皮山县| 清流县| 康马县| 阳曲县| 南靖县| 巴东县| 南安市| 云龙县| 宁德市| 黎川县| 横峰县| 桂林市| 广德县| 桐柏县| 阜宁县| 尤溪县| 武义县| 嘉定区| 东乌珠穆沁旗| 普宁市| 武义县| 灵宝市| 景洪市| 高陵县| 社旗县| 图木舒克市| 怀来县| 横山县| 唐河县| 平邑县| 蒙自县| 玉山县| 灌南县|