Linux系統編程入門(一)

服務器項目課程學習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 }

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章