Linux系統(tǒng)編程入門(一)
服務(wù)器項(xiàng)目課程學(xué)習(xí)20220221
Linux系統(tǒng)編程入門(一)
GCC
什么是GCC

編程語(yǔ)言的發(fā)展
計(jì)算機(jī)<--(運(yùn)行)---機(jī)器語(yǔ)言<---(匯編)-----匯編語(yǔ)言<----(編譯)----高級(jí)語(yǔ)言

GCC工程流程
源代碼---(預(yù)處理器)----->預(yù)處理后源代碼(.i)---->編譯器----->匯編代碼------>匯編器---->目標(biāo)代碼/啟動(dòng)代碼/庫(kù)代碼/其他目標(biāo)代碼------->鏈接器------>可執(zhí)行文件(.exe/.out)
.h
.c
.cpp

gcc和g++的區(qū)別
都是GNU(組織)的一個(gè)編譯器。


GCC常用參數(shù)


靜態(tài)庫(kù)的制作和使用
什么是庫(kù)

靜態(tài)庫(kù)的制作

makefile
什么是makefile

makefile文件命名和規(guī)則

makefile工作原理

變量

makefile和GDB調(diào)試
makefile
變量

模式匹配

函數(shù)


GDB調(diào)試
什么是GDB調(diào)試

準(zhǔn)備工作

GDB命令-啟動(dòng)、退出、查看代碼

GDB命令-斷點(diǎn)操作

GDB命令-調(diào)試命令

標(biāo)準(zhǔn)C庫(kù)IO函數(shù)和Linux系統(tǒng)IO函數(shù)的對(duì)比
IO函數(shù)是站在內(nèi)存的角度輸入輸出
標(biāo)準(zhǔn)C庫(kù)IO函數(shù)(第三方庫(kù)IO函數(shù))

標(biāo)準(zhǔn)C庫(kù)IO和Linux系統(tǒng)IO的關(guān)系

虛擬地址空間
虛擬地址空間
虛擬地址空間是不存在的,是想象出來(lái)的,是用來(lái)干啥的呢?
程序和進(jìn)程的區(qū)別:程序只是在磁盤上的代碼。運(yùn)行中的代碼加載到內(nèi)存中,是進(jìn)程,進(jìn)程也就是運(yùn)行中的程序。
MMU:內(nèi)存管理單元

文件描述符
文件描述符

open打開文件


open打開文件的代碼框架

open創(chuàng)建新文件
man 2是linux系統(tǒng)的內(nèi)容,man 3是標(biāo)準(zhǔn)庫(kù)里面的內(nèi)容。
open函數(shù)的使用



read、write函數(shù)


代碼:
1 /*
2 #include <unistd.h>
3 ssize_t read(int fd, void *buf, size_t count);
4 參數(shù):
5 - fd:文件描述符,open得到的,通過(guò)這個(gè)文件描述符操作某個(gè)文件
6 - buf:需要讀取數(shù)據(jù)存放的地方,數(shù)組的地址(傳出參數(shù))
7 - count:指定的數(shù)組的大小
8 返回值:
9 - 成功:
10 >0: 返回實(shí)際的讀取到的字節(jié)數(shù)
11 =0:文件已經(jīng)讀取完了
12 - 失敗:-1 ,并且設(shè)置errno
13
14 #include <unistd.h>
15 ssize_t write(int fd, const void *buf, size_t count);
16 參數(shù):
17 - fd:文件描述符,open得到的,通過(guò)這個(gè)文件描述符操作某個(gè)文件
18 - buf:要往磁盤寫入的數(shù)據(jù),數(shù)據(jù)
19 - count:要寫的數(shù)據(jù)的實(shí)際的大小
20 返回值:
21 成功:實(shí)際寫入的字節(jié)數(shù)
22 失敗:返回-1,并設(shè)置errno
23 */
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 int main() {
31
32 // 1.通過(guò)open打開english.txt文件
33 int srcfd = open("english.txt", O_RDONLY);
34 if(srcfd == -1) {
35 perror("open");
36 return -1;
37 }
38
39 // 2.創(chuàng)建一個(gè)新的文件(拷貝文件)
40 int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
41 if(destfd == -1) {
42 perror("open");
43 return -1;
44 }
45
46 // 3.頻繁的讀寫操作
47 char buf[1024] = {0};
48 int len = 0;
49 while((len = read(srcfd, buf, sizeof(buf))) > 0) {
50 write(destfd, buf, len);
51 }
52
53 // 4.關(guān)閉文件
54 close(destfd);
55 close(srcfd);
56
57
58 return 0;
59 }
lseek函數(shù)


代碼:
1 /*
2 標(biāo)準(zhǔn)C庫(kù)的函數(shù)
3 #include <stdio.h>
4 int fseek(FILE *stream, long offset, int whence);
5
6 Linux系統(tǒng)函數(shù)
7 #include <sys/types.h>
8 #include <unistd.h>
9 off_t lseek(int fd, off_t offset, int whence);
10 參數(shù):
11 - fd:文件描述符,通過(guò)open得到的,通過(guò)這個(gè)fd操作某個(gè)文件
12 - offset:偏移量
13 - whence:
14 SEEK_SET
15 設(shè)置文件指針的偏移量
16 SEEK_CUR
17 設(shè)置偏移量:當(dāng)前位置 + 第二個(gè)參數(shù)offset的值
18 SEEK_END
19 設(shè)置偏移量:文件大小 + 第二個(gè)參數(shù)offset的值
20 返回值:返回文件指針的位置
21
22
23 作用:
24 1.移動(dòng)文件指針到文件頭
25 lseek(fd, 0, SEEK_SET);
26
27 2.獲取當(dāng)前文件指針的位置
28 lseek(fd, 0, SEEK_CUR);
29
30 3.獲取文件長(zhǎng)度
31 lseek(fd, 0, SEEK_END);
32
33 4.拓展文件的長(zhǎng)度,當(dāng)前文件10b, 110b, 增加了100個(gè)字節(jié)
34 lseek(fd, 100, SEEK_END)
35 注意:需要寫一次數(shù)據(jù)
36
37 */
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <stdio.h>
44
45 int main() {
46
47 int fd = open("hello.txt", O_RDWR);
48
49 if(fd == -1) {
50 perror("open");
51 return -1;
52 }
53
54 // 擴(kuò)展文件的長(zhǎng)度
55 int ret = lseek(fd, 100, SEEK_END);
56 if(ret == -1) {
57 perror("lseek");
58 return -1;
59 }
60
61 // 寫入一個(gè)空數(shù)據(jù)
62 write(fd, " ", 1);
63
64 // 關(guān)閉文件
65 close(fd);
66
67 return 0;
68 }
stat、lstat函數(shù)

stat結(jié)構(gòu)體


代碼:
1 /*
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5
6 int stat(const char *pathname, struct stat *statbuf);
7 作用:獲取一個(gè)文件相關(guān)的一些信息
8 參數(shù):
9 - pathname:操作的文件的路徑
10 - statbuf:結(jié)構(gòu)體變量,傳出參數(shù),用于保存獲取到的文件的信息
11 返回值:
12 成功:返回0
13 失敗:返回-1 設(shè)置errno
14
15 int lstat(const char *pathname, struct stat *statbuf);
16 參數(shù):
17 - pathname:操作的文件的路徑
18 - statbuf:結(jié)構(gòu)體變量,傳出參數(shù),用于保存獲取到的文件的信息
19 返回值:
20 成功:返回0
21 失敗:返回-1 設(shè)置errno
22
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdio.h>
29
30 int main() {
31
32 struct stat statbuf;
33
34 int ret = stat("a.txt", &statbuf);
35
36 if(ret == -1) {
37 perror("stat");
38 return -1;
39 }
40
41 printf("size: %ld\n", statbuf.st_size);
42
43
44 return 0;
45 }
模擬實(shí)現(xiàn)ls -l命令
第一個(gè)是模擬的, 第二個(gè)是直接的不是模擬的。

代碼:
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5 #include <pwd.h>
6 #include <grp.h>
7 #include <time.h>
8 #include <string.h>
9
10 // 模擬實(shí)現(xiàn) ls -l 指令
11 // -rw-rw-r-- 1 nowcoder nowcoder 12 12月 3 15:48 a.txt
12 int main(int argc, char * argv[]) {
13
14 // 判斷輸入的參數(shù)是否正確
15 if(argc < 2) {
16 printf("%s filename\n", argv[0]);
17 return -1;
18 }
19
20 // 通過(guò)stat函數(shù)獲取用戶傳入的文件的信息
21 struct stat st;
22 int ret = stat(argv[1], &st);
23 if(ret == -1) {
24 perror("stat");
25 return -1;
26 }
27
28 // 獲取文件類型和文件權(quán)限
29 char perms[11] = {0}; // 用于保存文件類型和文件權(quán)限的字符串
30
31 switch(st.st_mode & S_IFMT) {
32 case S_IFLNK:
33 perms[0] = 'l';
34 break;
35 case S_IFDIR:
36 perms[0] = 'd';
37 break;
38 case S_IFREG:
39 perms[0] = '-';
40 break;
41 case S_IFBLK:
42 perms[0] = 'b';
43 break;
44 case S_IFCHR:
45 perms[0] = 'c';
46 break;
47 case S_IFSOCK:
48 perms[0] = 's';
49 break;
50 case S_IFIFO:
51 perms[0] = 'p';
52 break;
53 default:
54 perms[0] = '?';
55 break;
56 }
57
58 // 判斷文件的訪問(wèn)權(quán)限
59
60 // 文件所有者
61 perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
62 perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
63 perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
64
65 // 文件所在組
66 perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
67 perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
68 perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
69
70 // 其他人
71 perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
72 perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
73 perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
74
75 // 硬連接數(shù)
76 int linkNum = st.st_nlink;
77
78 // 文件所有者
79 char * fileUser = getpwuid(st.st_uid)->pw_name;
80
81 // 文件所在組
82 char * fileGrp = getgrgid(st.st_gid)->gr_name;
83
84 // 文件大小
85 long int fileSize = st.st_size;
86
87 // 獲取修改的時(shí)間
88 char * time = ctime(&st.st_mtime);
89
90 char mtime[512] = {0};
91 strncpy(mtime, time, strlen(time) - 1);
92
93 char buf[1024];
94 sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
95
96 printf("%s\n", buf);
97
98 return 0;
99 }
文件屬性操作函數(shù)



代碼:
1 /*
2 #include <sys/stat.h>
3 int chmod(const char *pathname, mode_t mode);
4 修改文件的權(quán)限
5 參數(shù):
6 - pathname: 需要修改的文件的路徑
7 - mode:需要修改的權(quán)限值,八進(jìn)制的數(shù)
8 返回值:成功返回0,失敗返回-1
9
10 */
11 #include <sys/stat.h>
12 #include <stdio.h>
13 int main() {
14
15 int ret = chmod("a.txt", 0777);
16
17 if(ret == -1) {
18 perror("chmod");
19 return -1;
20 }
21
22 return 0;
23 }
1 /*
2 #include <unistd.h>
3 int access(const char *pathname, int mode);
4 作用:判斷某個(gè)文件是否有某個(gè)權(quán)限,或者判斷文件是否存在
5 參數(shù):
6 - pathname: 判斷的文件路徑
7 - mode:
8 R_OK: 判斷是否有讀權(quán)限
9 W_OK: 判斷是否有寫權(quán)限
10 X_OK: 判斷是否有執(zhí)行權(quán)限
11 F_OK: 判斷文件是否存在
12 返回值:成功返回0, 失敗返回-1
13 */
14
15 #include <unistd.h>
16 #include <stdio.h>
17
18 int main() {
19
20 int ret = access("a.txt", F_OK);
21 if(ret == -1) {
22 perror("access");
23 }
24
25 printf("文件存在!!!\n");
26
27 return 0;
28 }
1 /*
2 #include <unistd.h>
3 #include <sys/types.h>
4 int truncate(const char *path, off_t length);
5 作用:縮減或者擴(kuò)展文件的尺寸至指定的大小
6 參數(shù):
7 - path: 需要修改的文件的路徑
8 - length: 需要最終文件變成的大小
9 返回值:
10 成功返回0, 失敗返回-1
11 */
12
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <stdio.h>
16
17 int main() {
18
19 int ret = truncate("b.txt", 5);
20
21 if(ret == -1) {
22 perror("truncate");
23 return -1;
24 }
25
26 return 0;
27 }
目錄操作函數(shù)

代碼:
1 /*
2 #include <sys/stat.h>
3 #include <sys/types.h>
4 int mkdir(const char *pathname, mode_t mode);
5 作用:創(chuàng)建一個(gè)目錄
6 參數(shù):
7 pathname: 創(chuàng)建的目錄的路徑
8 mode: 權(quán)限,八進(jìn)制的數(shù)
9 返回值:
10 成功返回0, 失敗返回-1
11 */
12
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <stdio.h>
16
17 int main() {
18
19 int ret = mkdir("aaa", 0777);
20
21 if(ret == -1) {
22 perror("mkdir");
23 return -1;
24 }
25
26 return 0;
27 }
1 /*
2 #include <stdio.h>
3 int rename(const char *oldpath, const char *newpath);
4
5 */
6 #include <stdio.h>
7
8 int main() {
9
10 int ret = rename("aaa", "bbb");
11
12 if(ret == -1) {
13 perror("rename");
14 return -1;
15 }
16
17 return 0;
18 }
1 /*
2
3 #include <unistd.h>
4 int chdir(const char *path);
5 作用:修改進(jìn)程的工作目錄
6 比如在/home/nowcoder 啟動(dòng)了一個(gè)可執(zhí)行程序a.out, 進(jìn)程的工作目錄 /home/nowcoder
7 參數(shù):
8 path : 需要修改的工作目錄
9
10 #include <unistd.h>
11 char *getcwd(char *buf, size_t size);
12 作用:獲取當(dāng)前工作目錄
13 參數(shù):
14 - buf : 存儲(chǔ)的路徑,指向的是一個(gè)數(shù)組(傳出參數(shù))
15 - size: 數(shù)組的大小
16 返回值:
17 返回的指向的一塊內(nèi)存,這個(gè)數(shù)據(jù)就是第一個(gè)參數(shù)
18
19 */
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <fcntl.h>
25
26 int main() {
27
28 // 獲取當(dāng)前的工作目錄
29 char buf[128];
30 getcwd(buf, sizeof(buf));
31 printf("當(dāng)前的工作目錄是:%s\n", buf);
32
33 // 修改工作目錄
34 int ret = chdir("/home/nowcoder/Linux/lesson13");
35 if(ret == -1) {
36 perror("chdir");
37 return -1;
38 }
39
40 // 創(chuàng)建一個(gè)新的文件
41 int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);
42 if(fd == -1) {
43 perror("open");
44 return -1;
45 }
46
47 close(fd);
48
49 // 獲取當(dāng)前的工作目錄
50 char buf1[128];
51 getcwd(buf1, sizeof(buf1));
52 printf("當(dāng)前的工作目錄是:%s\n", buf1);
53
54 return 0;
55 }
目錄遍歷函數(shù)

dirent結(jié)構(gòu)體和d_type

代碼:
1 /*
2 // 打開一個(gè)目錄
3 #include <sys/types.h>
4 #include <dirent.h>
5 DIR *opendir(const char *name);
6 參數(shù):
7 - name: 需要打開的目錄的名稱
8 返回值:
9 DIR * 類型,理解為目錄流
10 錯(cuò)誤返回NULL
11
12
13 // 讀取目錄中的數(shù)據(jù)
14 #include <dirent.h>
15 struct dirent *readdir(DIR *dirp);
16 - 參數(shù):dirp是opendir返回的結(jié)果
17 - 返回值:
18 struct dirent,代表讀取到的文件的信息
19 讀取到了末尾或者失敗了,返回NULL
20
21 // 關(guān)閉目錄
22 #include <sys/types.h>
23 #include <dirent.h>
24 int closedir(DIR *dirp);
25
26 */
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 int getFileNum(const char * path);
34
35 // 讀取某個(gè)目錄下所有的普通文件的個(gè)數(shù)
36 int main(int argc, char * argv[]) {
37
38 if(argc < 2) {
39 printf("%s path\n", argv[0]);
40 return -1;
41 }
42
43 int num = getFileNum(argv[1]);
44
45 printf("普通文件的個(gè)數(shù)為:%d\n", num);
46
47 return 0;
48 }
49
50 // 用于獲取目錄下所有普通文件的個(gè)數(shù)
51 int getFileNum(const char * path) {
52
53 // 1.打開目錄
54 DIR * dir = opendir(path);
55
56 if(dir == NULL) {
57 perror("opendir");
58 exit(0);
59 }
60
61 struct dirent *ptr;
62
63 // 記錄普通文件的個(gè)數(shù)
64 int total = 0;
65
66 while((ptr = readdir(dir)) != NULL) {
67
68 // 獲取名稱
69 char * dname = ptr->d_name;
70
71 // 忽略掉. 和..
72 if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
73 continue;
74 }
75
76 // 判斷是否是普通文件還是目錄
77 if(ptr->d_type == DT_DIR) {
78 // 目錄,需要繼續(xù)讀取這個(gè)目錄
79 char newpath[256];
80 sprintf(newpath, "%s/%s", path, dname);
81 total += getFileNum(newpath);
82 }
83
84 if(ptr->d_type == DT_REG) {
85 // 普通文件
86 total++;
87 }
88
89
90 }
91
92 // 關(guān)閉目錄
93 closedir(dir);
94
95 return total;
96 }
dup、dup2函數(shù)

代碼:
1 /*
2 #include <unistd.h>
3 int dup(int oldfd);
4 作用:復(fù)制一個(gè)新的文件描述符
5 fd=3, int fd1 = dup(fd),
6 fd指向的是a.txt, fd1也是指向a.txt
7 從空閑的文件描述符表中找一個(gè)最小的,作為新的拷貝的文件描述符
8
9
10 */
11
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <string.h>
18
19 int main() {
20
21 int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
22
23 int fd1 = dup(fd);
24
25 if(fd1 == -1) {
26 perror("dup");
27 return -1;
28 }
29
30 printf("fd : %d , fd1 : %d\n", fd, fd1);
31
32 close(fd);
33
34 char * str = "hello,world";
35 int ret = write(fd1, str, strlen(str));
36 if(ret == -1) {
37 perror("write");
38 return -1;
39 }
40
41 close(fd1);
42
43 return 0;
44 }
1 /*
2 #include <unistd.h>
3 int dup2(int oldfd, int newfd);
4 作用:重定向文件描述符
5 oldfd 指向 a.txt, newfd 指向 b.txt
6 調(diào)用函數(shù)成功后:newfd 和 b.txt 做close, newfd 指向了 a.txt
7 oldfd 必須是一個(gè)有效的文件描述符
8 oldfd和newfd值相同,相當(dāng)于什么都沒有做
9 */
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <fcntl.h>
16
17 int main() {
18
19 int fd = open("1.txt", O_RDWR | O_CREAT, 0664);
20 if(fd == -1) {
21 perror("open");
22 return -1;
23 }
24
25 int fd1 = open("2.txt", O_RDWR | O_CREAT, 0664);
26 if(fd1 == -1) {
27 perror("open");
28 return -1;
29 }
30
31 printf("fd : %d, fd1 : %d\n", fd, fd1);
32
33 int fd2 = dup2(fd, fd1);
34 if(fd2 == -1) {
35 perror("dup2");
36 return -1;
37 }
38
39 // 通過(guò)fd1去寫數(shù)據(jù),實(shí)際操作的是1.txt,而不是2.txt
40 char * str = "hello, dup2";
41 int len = write(fd1, str, strlen(str));
42
43 if(len == -1) {
44 perror("write");
45 return -1;
46 }
47
48 printf("fd : %d, fd1 : %d, fd2 : %d\n", fd, fd1, fd2);
49
50 close(fd);
51 close(fd1);
52
53 return 0;
54 }
fcntl函數(shù)
代碼:
1 /*
2
3 #include <unistd.h>
4 #include <fcntl.h>
5
6 int fcntl(int fd, int cmd, ...);
7 參數(shù):
8 fd : 表示需要操作的文件描述符
9 cmd: 表示對(duì)文件描述符進(jìn)行如何操作
10 - F_DUPFD : 復(fù)制文件描述符,復(fù)制的是第一個(gè)參數(shù)fd,得到一個(gè)新的文件描述符(返回值)
11 int ret = fcntl(fd, F_DUPFD);
12
13 - F_GETFL : 獲取指定的文件描述符文件狀態(tài)flag
14 獲取的flag和我們通過(guò)open函數(shù)傳遞的flag是一個(gè)東西。
15
16 - F_SETFL : 設(shè)置文件描述符文件狀態(tài)flag
17 必選項(xiàng):O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
18 可選性:O_APPEND, O)NONBLOCK
19 O_APPEND 表示追加數(shù)據(jù)
20 NONBLOK 設(shè)置成非阻塞
21
22 阻塞和非阻塞:描述的是函數(shù)調(diào)用的行為。
23 */
24
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 int main() {
31
32 // 1.復(fù)制文件描述符
33 // int fd = open("1.txt", O_RDONLY);
34 // int ret = fcntl(fd, F_DUPFD);
35
36 // 2.修改或者獲取文件狀態(tài)flag
37 int fd = open("1.txt", O_RDWR);
38 if(fd == -1) {
39 perror("open");
40 return -1;
41 }
42
43 // 獲取文件描述符狀態(tài)flag
44 int flag = fcntl(fd, F_GETFL);
45 if(flag == -1) {
46 perror("fcntl");
47 return -1;
48 }
49 flag |= O_APPEND; // flag = flag | O_APPEND
50
51 // 修改文件描述符狀態(tài)的flag,給flag加入O_APPEND這個(gè)標(biāo)記
52 int ret = fcntl(fd, F_SETFL, flag);
53 if(ret == -1) {
54 perror("fcntl");
55 return -1;
56 }
57
58 char * str = "nihao";
59 write(fd, str, strlen(str));
60
61 close(fd);
62
63 return 0;
64 }
雪兒言


浙公網(wǎng)安備 33010602011771號(hào)