服務器項目課程學習20220221
Linux系統編程入門(一)
GCC
什麼是GCC
編程語言的發展
計算機<--(運行)---機器語言<---(彙編)-----彙編語言<----(編譯)----高級語言
GCC工程流程
源代碼---(預處理器)----->預處理後源代碼(.i)---->編譯器----->彙編代碼------>彙編器---->目標代碼/啓動代碼/庫代碼/其他目標代碼------->鏈接器------>可執行文件(.exe/.out)
.h
.c
.cpp
gcc和g++的區別
都是GNU(組織)的一個編譯器。
GCC常用參數
靜態庫的製作和使用
什麼是庫
靜態庫的製作
makefile
什麼是makefile
makefile文件命名和規則
makefile工作原理
變量
makefile和GDB調試
makefile
變量
模式匹配
函數
GDB調試
什麼是GDB調試
準備工作
GDB命令-啓動、退出、查看代碼
GDB命令-斷點操作
GDB命令-調試命令
標準C庫IO函數和Linux系統IO函數的對比
IO函數是站在內存的角度輸入輸出
標準C庫IO函數(第三方庫IO函數)
標準C庫IO和Linux系統IO的關係
虛擬地址空間
虛擬地址空間
虛擬地址空間是不存在的,是想象出來的,是用來幹啥的呢?
程序和進程的區別:程序只是在磁盤上的代碼。運行中的代碼加載到內存中,是進程,進程也就是運行中的程序。
MMU:內存管理單元
文件描述符
文件描述符
open打開文件
open打開文件的代碼框架
open創建新文件
man 2是linux系統的內容,man 3是標準庫裏面的內容。
open函數的使用
read、write函數
代碼:
1 /*
2 #include <unistd.h>
3 ssize_t read(int fd, void *buf, size_t count);
4 參數:
5 - fd:文件描述符,open得到的,通過這個文件描述符操作某個文件
6 - buf:需要讀取數據存放的地方,數組的地址(傳出參數)
7 - count:指定的數組的大小
8 返回值:
9 - 成功:
10 >0: 返回實際的讀取到的字節數
11 =0:文件已經讀取完了
12 - 失敗:-1 ,並且設置errno
13
14 #include <unistd.h>
15 ssize_t write(int fd, const void *buf, size_t count);
16 參數:
17 - fd:文件描述符,open得到的,通過這個文件描述符操作某個文件
18 - buf:要往磁盤寫入的數據,數據
19 - count:要寫的數據的實際的大小
20 返回值:
21 成功:實際寫入的字節數
22 失敗:返回-1,並設置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.通過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.創建一個新的文件(拷貝文件)
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.關閉文件
54 close(destfd);
55 close(srcfd);
56
57
58 return 0;
59 }
lseek函數
代碼:
1 /*
2 標準C庫的函數
3 #include <stdio.h>
4 int fseek(FILE *stream, long offset, int whence);
5
6 Linux系統函數
7 #include <sys/types.h>
8 #include <unistd.h>
9 off_t lseek(int fd, off_t offset, int whence);
10 參數:
11 - fd:文件描述符,通過open得到的,通過這個fd操作某個文件
12 - offset:偏移量
13 - whence:
14 SEEK_SET
15 設置文件指針的偏移量
16 SEEK_CUR
17 設置偏移量:當前位置 + 第二個參數offset的值
18 SEEK_END
19 設置偏移量:文件大小 + 第二個參數offset的值
20 返回值:返回文件指針的位置
21
22
23 作用:
24 1.移動文件指針到文件頭
25 lseek(fd, 0, SEEK_SET);
26
27 2.獲取當前文件指針的位置
28 lseek(fd, 0, SEEK_CUR);
29
30 3.獲取文件長度
31 lseek(fd, 0, SEEK_END);
32
33 4.拓展文件的長度,當前文件10b, 110b, 增加了100個字節
34 lseek(fd, 100, SEEK_END)
35 注意:需要寫一次數據
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 // 擴展文件的長度
55 int ret = lseek(fd, 100, SEEK_END);
56 if(ret == -1) {
57 perror("lseek");
58 return -1;
59 }
60
61 // 寫入一個空數據
62 write(fd, " ", 1);
63
64 // 關閉文件
65 close(fd);
66
67 return 0;
68 }
stat、lstat函數
stat結構體
代碼:
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 作用:獲取一個文件相關的一些信息
8 參數:
9 - pathname:操作的文件的路徑
10 - statbuf:結構體變量,傳出參數,用於保存獲取到的文件的信息
11 返回值:
12 成功:返回0
13 失敗:返回-1 設置errno
14
15 int lstat(const char *pathname, struct stat *statbuf);
16 參數:
17 - pathname:操作的文件的路徑
18 - statbuf:結構體變量,傳出參數,用於保存獲取到的文件的信息
19 返回值:
20 成功:返回0
21 失敗:返回-1 設置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 }
模擬實現ls -l命令
第一個是模擬的, 第二個是直接的不是模擬的。
代碼:
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 // 模擬實現 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 // 判斷輸入的參數是否正確
15 if(argc < 2) {
16 printf("%s filename\n", argv[0]);
17 return -1;
18 }
19
20 // 通過stat函數獲取用戶傳入的文件的信息
21 struct stat st;
22 int ret = stat(argv[1], &st);
23 if(ret == -1) {
24 perror("stat");
25 return -1;
26 }
27
28 // 獲取文件類型和文件權限
29 char perms[11] = {0}; // 用於保存文件類型和文件權限的字符串
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 // 判斷文件的訪問權限
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 // 硬連接數
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 // 獲取修改的時間
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 }
文件屬性操作函數
代碼:
1 /*
2 #include <sys/stat.h>
3 int chmod(const char *pathname, mode_t mode);
4 修改文件的權限
5 參數:
6 - pathname: 需要修改的文件的路徑
7 - mode:需要修改的權限值,八進制的數
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 作用:判斷某個文件是否有某個權限,或者判斷文件是否存在
5 參數:
6 - pathname: 判斷的文件路徑
7 - mode:
8 R_OK: 判斷是否有讀權限
9 W_OK: 判斷是否有寫權限
10 X_OK: 判斷是否有執行權限
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 作用:縮減或者擴展文件的尺寸至指定的大小
6 參數:
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 }
目錄操作函數
代碼:
1 /*
2 #include <sys/stat.h>
3 #include <sys/types.h>
4 int mkdir(const char *pathname, mode_t mode);
5 作用:創建一個目錄
6 參數:
7 pathname: 創建的目錄的路徑
8 mode: 權限,八進制的數
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 作用:修改進程的工作目錄
6 比如在/home/nowcoder 啓動了一個可執行程序a.out, 進程的工作目錄 /home/nowcoder
7 參數:
8 path : 需要修改的工作目錄
9
10 #include <unistd.h>
11 char *getcwd(char *buf, size_t size);
12 作用:獲取當前工作目錄
13 參數:
14 - buf : 存儲的路徑,指向的是一個數組(傳出參數)
15 - size: 數組的大小
16 返回值:
17 返回的指向的一塊內存,這個數據就是第一個參數
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 // 獲取當前的工作目錄
29 char buf[128];
30 getcwd(buf, sizeof(buf));
31 printf("當前的工作目錄是:%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 // 創建一個新的文件
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 // 獲取當前的工作目錄
50 char buf1[128];
51 getcwd(buf1, sizeof(buf1));
52 printf("當前的工作目錄是:%s\n", buf1);
53
54 return 0;
55 }
目錄遍歷函數
dirent結構體和d_type
代碼:
1 /*
2 // 打開一個目錄
3 #include <sys/types.h>
4 #include <dirent.h>
5 DIR *opendir(const char *name);
6 參數:
7 - name: 需要打開的目錄的名稱
8 返回值:
9 DIR * 類型,理解爲目錄流
10 錯誤返回NULL
11
12
13 // 讀取目錄中的數據
14 #include <dirent.h>
15 struct dirent *readdir(DIR *dirp);
16 - 參數:dirp是opendir返回的結果
17 - 返回值:
18 struct dirent,代表讀取到的文件的信息
19 讀取到了末尾或者失敗了,返回NULL
20
21 // 關閉目錄
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 // 讀取某個目錄下所有的普通文件的個數
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("普通文件的個數爲:%d\n", num);
46
47 return 0;
48 }
49
50 // 用於獲取目錄下所有普通文件的個數
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 // 記錄普通文件的個數
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 // 目錄,需要繼續讀取這個目錄
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 // 關閉目錄
93 closedir(dir);
94
95 return total;
96 }
dup、dup2函數
代碼:
1 /*
2 #include <unistd.h>
3 int dup(int oldfd);
4 作用:複製一個新的文件描述符
5 fd=3, int fd1 = dup(fd),
6 fd指向的是a.txt, fd1也是指向a.txt
7 從空閒的文件描述符表中找一個最小的,作爲新的拷貝的文件描述符
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 調用函數成功後:newfd 和 b.txt 做close, newfd 指向了 a.txt
7 oldfd 必須是一個有效的文件描述符
8 oldfd和newfd值相同,相當於什麼都沒有做
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 // 通過fd1去寫數據,實際操作的是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函數
代碼:
1 /*
2
3 #include <unistd.h>
4 #include <fcntl.h>
5
6 int fcntl(int fd, int cmd, ...);
7 參數:
8 fd : 表示需要操作的文件描述符
9 cmd: 表示對文件描述符進行如何操作
10 - F_DUPFD : 複製文件描述符,複製的是第一個參數fd,得到一個新的文件描述符(返回值)
11 int ret = fcntl(fd, F_DUPFD);
12
13 - F_GETFL : 獲取指定的文件描述符文件狀態flag
14 獲取的flag和我們通過open函數傳遞的flag是一個東西。
15
16 - F_SETFL : 設置文件描述符文件狀態flag
17 必選項:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
18 可選性:O_APPEND, O)NONBLOCK
19 O_APPEND 表示追加數據
20 NONBLOK 設置成非阻塞
21
22 阻塞和非阻塞:描述的是函數調用的行爲。
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.複製文件描述符
33 // int fd = open("1.txt", O_RDONLY);
34 // int ret = fcntl(fd, F_DUPFD);
35
36 // 2.修改或者獲取文件狀態flag
37 int fd = open("1.txt", O_RDWR);
38 if(fd == -1) {
39 perror("open");
40 return -1;
41 }
42
43 // 獲取文件描述符狀態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 // 修改文件描述符狀態的flag,給flag加入O_APPEND這個標記
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 }