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 }

 

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