• 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 }
     
  • 相关阅读:
    从buffer、cache区别看linux文件系统的内存管理
    Aspose.Cell C# 导出数据
    vagrant,VirtualBox 安装使用
    docker系列 安装rabbitmq
    supervisor安装以及监控管理rabbitmq消费者进程
    docker系列 安装PHP扩展
    the usage of const
    Linux内核printk打印ip地址
    【Groovy】groovy基本数据类型的简单用法
    jsdelivr 不能用了的替代方案
  • 原文地址:https://www.cnblogs.com/weixq351/p/15920873.html
Copyright © 2020-2023  润新知