• Linux 系统编程入门

    • 静态库与动态库

      • 静态库命名规则
      • 静态库的制作
      • 静态库使用
      • 动态库制作
      • 动态库使用
      • 加载动态库
      • 静态库的优缺点
      • 动态库的优缺点
    • Makefile
      • 文件命名
      • 工作原理
      • 变量
      • 模式匹配
      • 函数
    • GDB 调试
      • GDB 是什么?
      • 开始调试
      • gdb 指令
    • Linux系统IO函数
      • 标准C库IO函数
      • 虚拟地址空间(真实不存在)
      • 文件描述符
      • open 打开文件
      • create 文件
      • read 和 write
      • lseek 函数
      • stat 和 lstat 函数
      • 模拟实现 ls -l
      • 文件属性操作函数
      • 目录操作函数
      • 目录遍历函数
      • dup 和 dup2 函数
      • fcntl 函数

Linux 系统编程入门

静态库与动态库

静态库命名规则

  • linux: libxxx.a 保持 lib 前缀 和 .a 后缀
  • Windows: libxxx.lib

静态库的制作

gcc 获得 .o 文件 将 .o 文件用 ar 工具打包

ar rcs libxxx.a xxx.o xxx.o
# -r 将文件插入备份文件中
# -c 建立备份文件
# -s 索引

静态库使用

g++ main.cpp -I ./include  -l calc -L./lib -o test && ./test
# -I 包含路径
# -l 库名字
# -L 库路径

动态库制作

  • 命名规则

    • Linux: libxxx.so 保持 lib 前缀和 .so 后缀, 在linux 下是一个可执行文件
    • Windows: libxxx.dll
gcc -c -fpic *.c  # 得到和位置无关的代码
gcc -shared *.o -o libxxx.so  # 生成动态库
g++ main.cpp -I ./include -L lib/ -l calc -o main && ./main
# ./main: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

动态库使用

程序启动之后,动态库会被动态加载到内存,通过 ldd (list dynamic dependencies) 命令检查动态库依赖关系

ldd main
# linux-vdso.so.1 (0x00007ffd771f6000)
# libcalc.so => not found
# libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f47d0be9000)
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f47d09f7000)
# libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f47d08a8000)
# /lib64/ld-linux-x86-64.so.2 (0x00007f47d0e28000)
# libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f47d088d000)
  1. 如何定位共享库文件呢?

    当系统加载可执行代码时,能够知道其所依赖的库的名字,但还是需要知道绝对路径。

    • 搜索路径

      • elf 文件的 DT_RPATH 段
      • LD_LIBRARY_PATH
      • /etc/ld.so.cache 文件列表
      • /lib, /usr/lib

加载动态库

# 方法一, 临时用
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`/bin
./main
ldd main# 方法二, 用户级别
# 写到 .shrc 中# 方法三, 系统级别
# 写到 /etc/profile
  • 添加到文件列表
sudo nano /etc/ld.so.conf
sudo ldconfig

静态库的优缺点

  • 优点:

    • 静态库被打包到应用程序中加载速度快
    • 发布程序无需提供静态库,移植方便
  • 缺点

    • 消耗系统资源,浪费内存
    • 更新、部署、发布麻烦

动态库的优缺点

  • 优点:

    • 可以实现进程间资源共享(共享库)
    • 更新、部署、发布简单
    • 可以控制何时加载动态库
  • 缺点

    • 加载速度相对静态库慢
    • 发布程序时需要提供依赖的动态库

Makefile

  • Makefile 文件定义了一系列规则来编译指定文件。
  • make 一个命令行工具: 解释 Makefile 文件中指令的命令工具。

文件命名

  • makefile 或者 Makefile

  • 一个 Makefile 文件中可以有一个或多个规则

    • 目标 …: 依赖 …

      • 命令 (shell 命令)
  • 目标: 最终要生成的文件(伪目标除外)

  • 依赖: 生成目标所需要的文件或是目标

  • 命令: 通过执行命令对依赖操作生成目标(命令前必须 Tab 缩进)

  • Makefile 中的其他规则一般都是为第一条规则服务的

工作原理

  • 命令在执行之前, 需要先检查规则中的依赖是否存在

    • 如果存在, 执行命令
    • 如果不存在,向下检查其他规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令。
  • 检测更新,在执行规则中的命令是,会比较目标文件和依赖文件的时间

    • 如果依赖的时间比目标的时间晚,需要重新生成目标
    • 如果依赖的时间比目标时间早, 目标不需要更新,对应规则中的命令不需要被执行

变量

  • 自定义变量: 变量名=变量值 var=hello

  • 预定义变量:

    • AR: 归档维护程序的名称,默认值 ar
    • CC: C 编译器的名称, 默认值 cc
    • CXX: C++ 编译器的名称, 默认值 g++
    • $@: 目标的完整名称
  • 获取变量的值: $(变量名)

模式匹配

  • %.o:%.c

    • %: 通配符, 匹配一个字符串
    • 两个%匹配的是同一个字符串

函数

  • $(wildcard PATTERN)

    • 功能: 获取指定目录下指定类型的文件列表
    • 参数: PATTERN 指的是某个或多个目录下对应的某种类型的文件,如果有多个目录,一般使用空格间隔
    • 返回: 得到的若干个文件列表,文件名之间使用空格间隔
    • 示例: $(wildcard .cpp ./sub/.cpp)
      • 返回值: a.cpp b.cpp c.cpp
  • $(patsubst ,,)

    • 功能: 查找 text, 符合 patten, 用 replacement 替换
    • pattern 可以包含通配符 %, 表示任意长度的字串。如果 replacement 中也包含 %, 那么replacement 中的 % 与 patten 代表字串相同,可以用 \ 来转义。
    • 返回: 函数返回被替换过后的字符串
    • 示例: $(patsubst %.c, %.o, x.c bar.c)
      • 返回值格式: x.o bar.o

GDB 调试

GDB 是什么?

  • GDB 是由 GUN 软件系统社区提供的调试工具, 同 GCC 配套组成了一套完整的开发环境, GDB 是 Linux 和许多类 Unix 系统中的标准开发环境。

开始调试

  • 关掉编译器优化选项 (-O)
  • 打开调试选项 (-g) 在可执行文件中加入源代码的信息,比如可执行文件中的第几条机器指令对应源代码中的第几行,但不是嵌入源文件,调试时需要保证 gdb 能找到源文件。
  • (-Wall) 在不影响程序行为的情况下,打开所有 warning
g++ main.cpp -g -Wall -o test
gdb test

gdb 指令

  • 查看当前文件代码

    • list : 列出10行代码
    • list\l 行号 : 从指定行显示, 指定行在显示的中心位置
    • list\l 函数名 : 从指定函数显示
  • 查看非当前文件代码

    • list filename:line_number
    • list filename:function_name
  • 设置显示的行数

    • show list/listsize
    • set list/listsize
  • 回车 : 上一次命令

  • 设置断点

    • b/break 行号/函数名/文件名:行号/文件名:函数
  • 查看断点

    • i/info b/break
  • 删除断点

    • d/del/delete 断点编号
  • 设置断点无效

    • dis/disable 断点编号
  • 设置断点生效

    • ena/enable 断点编号
  • 设置断点条件

    • b/break 10 if i == 5
  • 运行gdb 程序

    • start 程序停在第一行
    • run 遇到断点才停
  • 继续运行, 到下一个断点才停

    • c/continue
  • 向下执行一行代码,不会进入函数体

    • n/next
  • 变量操作

    • p/print 变量名: 打印变量值
    • ptype 变量名: 打印变量类型
  • 向下单步调试,遇到函数进入函数体

    • s/step
    • finish 跳出函数体
  • 自动变量操作

    • display num, 自动打印指定变量的值
    • i/info display
    • undisplay 编号
  • 其他操作

    • set var 变量名=变量值
    • until, 跳出循环

Linux系统IO函数

标准C库IO函数

  • fopen, fclose, fread, fwrite, fgets, fputs, fscanf, fprintf, fseek, fgetc, fputc, ftell, feof, fflush…

  • 结构体: 文件描述符(整型值), 文件读写指针位置,IO缓冲区(内存地址)

用户程序 <–> C标准I/O库 <–> 内核(Read/Write) <–> 磁盘

虚拟地址空间(真实不存在)

Linux 下的可执行文件格式: ELF

用户区 内核区
0-3G 3G-4G

从左到右:

  • 用户区

    • 受保护的地址
    • .text (代码段,二进制机器指令)
    • .data (已初始化全局变量)
    • .bss (未初始化全局变量)
    • 堆空间 (大)
    • 共享库
    • 栈空间 (小)
    • 命令行参数
    • 环境变量
  • 内核区 内核空间是受保护的,用户不能对该空间进行读写操作,否则会出现段错误。

    • 内存管理
    • 进程管理
    • 设备驱动管理
    • VFS虚拟文件系统

文件描述符

  • PCB 进程控制块

  • 文件描述符

    • 0 -> stdin_fileno, 标准输入,默认打开
    • 1 -> stdout_fileno,标准输出,默认打开
    • 2 -> stderr_fileno, 标准错误, 默认打开
    • 3-1023 每打开一个新文件,占用一个文件描述符,而且是空闲的最小的一个文件描述符。

open 打开文件

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char **argv) {// 打开一个已经存在的文件// int open(const char* pathname, int flags);// int open(const char* pathname, int flags, mode_t mode );// 参数: pathname: 要创建的文件路径//       flags: 对文件的操作权限和其他设置//       mode: 八进制数,表示用户对新创建的文件的操作权限, 最终权限是 (mode & ~umask)// 返回一个新的文件描述符, 如果失败,返回 -1。// errno: 属于Linux 系统函数库, 库里面的一个全局变量,记录的是最近的错误号。/**#include<stdio.h>void perror(const char *s);作用: 打印 errno 对应的错误描述s 参数: 用户描述,比如 hello, 最终输出的内容的是 hello: xxx(实际的错误输出)*/int fd = open("./a.txt", O_RDONLY);if (-1 == fd) {perror("open");}close(fd);return 0;
}

create 文件

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {// 创建一个新的文件int fd = open("create.txt", O_RDWR |O_CREAT, 0775);if(-1 == fd) {perror("open create err");}close(fd);return 0;}

read 和 write

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {/**#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);参数: fd: 文件描述符, open得到,通过这个文件描述符操作某个文件buf: 需要读取数据存放的地方,数组的地址count: 指定数组的大小返回值: 成功, 大于0, 返回实际读取到的字节数, 0 文件读取完,失败-1 文件读取失败#include <unistd.h>         ssize_t write(int fd, const void *buf, size_t count);*/// 1. open 打开文件int fd = open("read_write.c", O_RDONLY);if(-1 == fd){perror("open err");return -1;}// 2. 创建一个新的文件(copy 文件)int dest_fd = open("cpy.txt", O_WRONLY| O_CREAT, 0777);if(-1 == dest_fd){perror("create err");return -1;}// 3. 频繁的读写操作char buffer[1024] = {0};int len = 0;while((len =   read(fd, buffer, sizeof(buffer))) > 0){write(dest_fd, buffer, len);}// 4. 关闭文件close(dest_fd);close(fd);return 0;
}

lseek 函数

  • 文件扩展功能
/**// 标准C库函数#include <stdio.h>int fseek(FILE *stream, long offset, int whence);// Linux 系统函数库#include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);参数:  fd: 通过 open 得到,文件描述符offset: 偏移量whence:  SEEK_SET 设置文件指针的偏移量SEEK_CUR 设置偏移量,当前位置 + 第二个参数的 offset 的值SEEK_END 设置偏移量,文件大小 + 第二个参数的 offset 的值返回值: 返回文件指针的位置作用: 1. 移动文件指针到文件头lseek(fd, 0, SEEK_SET);2. 获取当前文件指针的位置lseek(fd, 0,SEEK_SET);3. 获取文件长度lseek(fd, 0, SEEK_END);4. 扩展文件的长度, 当前文件 10b, 110b, 增加了100个字节lseek(fd, 100, SEEK_END)
*/#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {int fd = open("cpy.txt", O_RDWR);if (-1 == fd) {perror("read err");return -1;}// 扩展文件的长度int ret = lseek(fd, 100, SEEK_END);if (-1 == ret) {perror("lseek");return -1;}write(fd , " ", 1);close(fd);return 0;
}

注: 需要写一次数据才能改变大小

stat 和 lstat 函数

  • st_mode 变量: 一个16位的变量, 包含(文件类型, 特殊权限位,User, Group, Others)
  • (st_mode & S_IFMT) == S_IFREG
/**#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>int stat(const char *pathname, struct stat *statbuf);作用:获取一个文件相关的一些信息参数:- pathname: 操作文件的路径- statbuf: 结构体变量,传出参数,用于保存获取到的文件信息。返回值:- 成功: 返回0,- 失败: 返回-1, 设置 errnoint lstat(const char *pathname, struct stat *statbuf);作用: 获取软连接文件的信息
*/#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {struct stat statbuf;//  int ret = stat("cpy_s.txt", &statbuf);int ret = lstat("cpy_s.txt", &statbuf);if (-1 == ret) {perror("stat err");return -1;}printf("size: %1d\n", (int)statbuf.st_size);return 0;
}

模拟实现 ls -l

#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>/***/
int main(int argc, char *argv[]) {// 判断输入的参数是否正确if (argc < 2) {printf("%s filename\n", argv[0]);return -1;}// 通过 stat 过去文件的信息struct stat buffstat;int ret = stat(argv[1], &buffstat);if (-1 == ret) {perror("stat err");return -1;}// 获取文件类型和文件权限char permit[11] = {0};switch (buffstat.st_mode & S_IFMT) {case S_IFLNK:permit[0] = '1';break;case S_IFDIR:permit[0] = 'd';break;case S_IFREG:permit[0] = '-';break;case S_IFBLK:permit[0] = 'b';break;case S_IFSOCK:permit[0] = 's';break;case S_IFCHR:permit[0] = 'c';break;case S_IFIFO:permit[0] = 'p';break;default:permit[0] = '?';break;}// 判断文件的访问权限permit[1] = (buffstat.st_mode & S_IRUSR) ? 'r' : '-';permit[2] = (buffstat.st_mode & S_IWUSR) ? 'w' : '-';permit[3] = (buffstat.st_mode & S_IXUSR) ? 'x' : '-';permit[4] = (buffstat.st_mode & S_IRGRP) ? 'r' : '-';permit[5] = (buffstat.st_mode & S_IWGRP) ? 'w' : '-';permit[6] = (buffstat.st_mode & S_IXGRP) ? 'x' : '-';permit[7] = (buffstat.st_mode & S_IROTH) ? 'r' : '-';permit[8] = (buffstat.st_mode & S_IWOTH) ? 'w' : '-';permit[9] = (buffstat.st_mode & S_IXOTH) ? 'x' : '-';// 硬连接数int linkNum = buffstat.st_nlink;char *fileUser = getpwuid(buffstat.st_uid)->pw_name;char *fileGroup = getpwuid(buffstat.st_gid)->pw_name;// 文件大小long int fileSize = buffstat.st_size;// 获取修改时间char *changeTime = ctime(&buffstat.st_mtime);char mtime[512] = {0};strncpy(mtime, changeTime, strlen(changeTime) - 1);char buf[1024];sprintf(buf, "%s %d %s %s %ld %s %s", permit, linkNum, fileUser, fileGroup,fileSize, mtime, argv[1]);printf("%s\n", buf);return 0;
}

文件属性操作函数

  • access
  • 判断文件存在
/**#include <unistd.h>int access(const char *pathname, int mode);作用: 判断某个文件是否有某个权限, 或者判断文件是否存在参数: pathname: 判断文件路径mode: R_OK, W_OK, X_OK: 判断是否有相应权限返回值: 0 成功,-1 失败
*/#include <stdio.h>
#include <unistd.h>int main() {int ret = access("cpy.txt", R_OK);if (-1 == ret) {perror("access err");return -1;}printf("file exist!!! \n");return 0;
}
  • chmod
/**#include <sys/stat.h>int chmod(const char *pathname, mode_t mode);作用: 修改文件的权限参数: pathname: 要修改文件的路径mode:  需要修改的权限值,八进制的数返回值:成功 0, 失败 -1
*/
#include <stdio.h>
#include <sys/stat.h>int main() {int ret = chmod("cpy.txt", 0775);if (-1 == ret) {perror("chmod err");return -1;}return 0;
}
  • chown
/**#include <unistd.h>int chown(const char *pathname, uid_t owner, gid_t group);
*/
  • truncate
/**#include <sys/types.h>#include <unistd.h>int truncate(const char *path, off_t length);作用: 缩减或者扩展文件的尺寸到指定大小参数: path: 需要修改的文件的路径length: 需要最终文件变成的大小返回值: 成功 0, 失败 -1.
*/#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() {int ret = truncate("cpy.txt", 20);if (-1 == ret) {perror("truncate err");return -1;}return 0;
}

目录操作函数

  • mkdir
  • rmdir
  • rename
  • chdir
  • getcwd
/**// mkdir#include<sys/stat.h>#include <sys/types.h>int mkdir(const char *pathname, mode_t mode);参数: mode: 八进制的数// rmdir#include <unistd.h>int rmdir(const char *pathname);作用: 删除空目录// rename#include <stdio.h>int rename(const char *oldpath, const char *newpath);// chdir#include <unistd.h>int chdir(const char *path);作用:修改进程的工作目录// getcwd#include <unistd.h>char *getcwd(char *buf, size_t size);作用: 获取当前的工作目录参数: buf:存储的路径,指向的是一个数组(传出参数)size: 数组大小返回值: 返回的指向的一块内存, 这个数据就是第一个参数
*/#include <sys/unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(){// 获取当前的工作目录char buff[128];getcwd(buff, sizeof(buff));printf("current work path:%s \n", buff);// 修改工作目录int ret = chdir("../");int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);if(-1 == fd){perror("open err");return -1;}close(fd);// 获取当前的工作目录char buffCur[128];getcwd(buffCur, sizeof(buffCur));printf("now current work path: %s\n", buffCur);return 0;
}

目录遍历函数

  • opendir
  • readdir
  • closedir
/**#include <dirent.h>#include <sys/types.h>DIR *opendir(const char *name);参数:name : 需要打开的目录的名称返回值: DIR* 类型,理解为名录流,错误返回 NULL;#include <dirent.h>struct dirent *readdir(DIR *dirp);作用: 读取目录中的数据参数: dirp 通过 opendir 返回的结果返回值:struct dirent :代表读取到的文件信息,读取到末尾或失败,返回NULL;#include <dirent.h>#include <sys/types.h>int closedir(DIR *dirp);作用: 关闭目录
*/#include "string.h"
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>// 获取目录下所有普通文件的个数
int getFIleNumber(const char *path) {DIR *dir = opendir(path);if (dir == NULL) {perror("opendir");exit(0);}struct dirent *prt;int total_number = 0;while ((prt = readdir(dir))) {// 获取名称char *dname = prt->d_name;// 忽略 ./ 和 ../ 两个目录if (strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {continue;}// 判断是否是普通文件还是目录if (prt->d_type == DT_DIR) {// 目录, 需要继续读取这个目录char newPath[256];sprintf(newPath, "%s/%s", path, dname);total_number += getFIleNumber(newPath);}if (prt->d_type == DT_REG) {/// 普通文件++total_number;}}// 关闭目录closedir(dir);return total_number;
}// 读取某个目录下文件的个数
int main(int argc, char *argv[]) {if (argc < 2) {printf("%s path\n", argv[0]);return -1;}int file_numbers = getFIleNumber(argv[1]);printf("file numbers: %d\n", file_numbers);return 0;
}

dup 和 dup2 函数

  • dup 复制文件描述符
/**#include <unistd.h>int dup(int oldfd);作用: 复制一个新的文件描述符,和原来的文件描述符指向同一个文件,从空闲文件描述符表中找一个最小的,作为新的拷贝的文件描述符int dup2(int oldfd, int newfd);
*/#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {int fd1 = open("a.txt", O_RDWR | O_CREAT, 0664);int fd2 = dup(fd1);if (fd2 == -1) {perror("dup");return -1;}printf("fd1: %d, fd2: %d\n", fd1, fd2);close(fd1);char *str = "helloworld";int ret = write(fd2, str, strlen(str));if (-1 == ret) {perror("write");return -1;}close(fd2);return 0;
}
  • dup2 重定向文件描述符
/**#include <unistd.h>int dup(int oldfd);作用: 复制一个新的文件描述符,和原来的文件描述符指向同一个文件,从空闲文件描述符表中找一个最小的,作为新的拷贝的文件描述符int dup2(int oldfd, int newfd);作用: 重定向文件描述符,oldfd 指向 a.txt, newfd 指向 b.txt, 调用函数成功后, newfd 和 b.txtclose, newfd 指向了a.txt。 oldfd 必须是一个有效的文件描述符, oldfd 和 newfd相同,相当于什么都没做
*/#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {//int fd = open("1.txt", O_RDWR | O_CREAT, 0664);if (fd == -1) {perror("open");return -1;}int fd1 = open("2.txt", O_RDWR | O_CREAT, 0664);if (-1 == fd1) {perror("open");return -1;}printf("fd: %d, fd1 %d \n", fd, fd1);int fd2 = dup2(fd, fd1);if (fd2 == -1) {perror("dup2");return -1;}// 通过 fd1 去写数据, 实际操作的是 1.txt, 而不是 2.txtchar str[] = "hello dup2";int len = write(fd1, str, strlen(str));if (len == -1) {perror("write");return -1;}printf("fd: %d, fd1: %d, fd2: %d\n", fd, fd1, fd2);close(fd1);//  close(fd2);close(fd);return 0;
}

fcntl 函数

  • fcntl 复制文件描述符,设置、获取文件的状态标志
/**#include <fcntl.h>#include <unistd.h>int fcntl(int fd, int cmd, ... args);参数: fd 需要操作的文件描述符cmd : 表示对文件描述符进行如何操作1. 复制文件描述符, F_DUPFD2. F_GETFL 获取指定文件描述符状态 flag, 获取的flag 和通过 open传递的flag 是一个东西。3. F_SETFL 设置文件描述符状态 flag, 必选项 O_RDONLY, O_WRONLY, O_RDWR,可选项: O_APPEND, NONBLOCK, O_APPEND 表示追加数据, NONBLOK 设置能非阻塞。阻塞和非阻塞: 描述的是函数调用的行为。
*/#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {// 1. 复制文件描述符/* int fd = open("1.txt", O_RDONLY); *//* int ret = fcntl(fd , F_DUPFD); */// 2. 修改或者获取文件状态 flagint fd = open("1.txt", O_RDWR);if (-1 == fd) {perror("open");return -1;}// 获取文件描述符的状态int flag = fcntl(fd, F_GETFL);if (-1 == flag) {perror("fcntl");return -1;}flag |= O_APPEND;// 修改文件描述符状态的 flag, 给 flag 加入 O_APPEND 这个标记int ret = fcntl(fd, F_SETFL, flag);if (-1 == ret) {perror("fcntl");return -1;}char str[] = "\nhello world from fcntl\n";write(fd, str, strlen(str));close(fd);return 0;
}

【学习笔记】Linux 系统编程入门相关推荐

  1. 一文带你Linux系统编程入门

    文件和文件系统 文件是linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的. 文件描述符 在linux内核中,文件是用 ...

  2. 【北京迅为iMX6ULL】嵌入式学习之Linux系统编程视频教程

    什么是Linux系统编程? Linux系统编程也叫Linux下的高级编程,是介于应用层和驱动层之间的. 学习了哪些知识后可以学习Linux系统编程? C语言基础.Linux基本操作命令 怎么学习Lin ...

  3. 嵌入式学习之linux系统编程----1 了解linux编程并且在ubuntu以及ARM上运行测试程序

    1.何为linux系统编程? linux系统编程也称为linux下的高级编程,它介于应用层与驱动层之间. 一般来说分为三个层面,分别是:应用层(写一个qt程序或者c程序就属于是应用层面).驱动层(比如 ...

  4. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

  5. 【Linux】Linux系统编程(入门与系统编程)(一)(环境搭建、常见指令以及权限理解)

    目录 linux系统编程 : 1.推动技术进步的基本模式 2.理解操作系统的发展 Linux 背景介绍 UNIX发展的历史: Linux发展历史 开源 Linux的发行版本: a.技术角度 b.商业化 ...

  6. Linux 高并发服务器实战 - 1 Linux系统编程入门

    Linux 高并发服务器实战-1Linux系统编程入门 在本机和服务器端设置公共密钥(配置免密登录) 在本机cmd里输入 ssh-keygen -t rsa,生成本机的公密钥 在服务器端里也配置 ss ...

  7. 【Linux】Linux系统编程(入门与系统编程)(三)(深入理解操作系统、进程、环境变量、内存分布)

    本博客操作系统最多涉及30%的理论,重点在于部分进程的内容,部分文件系统的内容,部分文件管理的内容不是主讲操作系统,我们的最终目的是理解系统中最高频的知识点,然后被完全利用指导我们编程. 下面是这三篇 ...

  8. 学习笔记----MATLAB面向对象编程入门02--类的方法、构造函数

    本系列内容为<MATLAB面向对象编程–从入门到设计模式>学习笔记,特此说明. 定义类的方法 类的方法(Method)一般用来查询(Query)对象的状态,或者向对象发出一个命令(Comm ...

  9. 嵌入式学习笔记-linux应用编程和网络编程-3.2 文件属性

    一.linux中各种文件类型 1.普通文件(- regular file) 文本文件.文件中的内容是由文本构成的,文本指的是ASCII码字符.文件里的内容本质上都是数字(不管什么文件内容本质上都是数字 ...

最新文章

  1. python教程:关于 [lambda x: x*i for i in range(4)] 理解
  2. 云效产品体验征文——说出你和云效的故事
  3. 如何正确的终止正在运行的子线程
  4. Android之实现夸克浏览器书签和历史页面滑动时候右上角图标切换效果
  5. mysqldump文件中有SET @@SESSION.SQL_LOG_BIN= 0;解决方法
  6. html 左边固定右边自动,七种实现左侧固定,右侧自适应两栏布局的方法
  7. 案例:对比使用Java代码与EL表达式获取信息
  8. 竖流式沉淀池集水槽设计计算_竖流沉淀池计算书
  9. 惰性函数定义模式 网页设计
  10. sublime3安装常用插件
  11. 二、常量、变量和基本数据类型
  12. bzoj1458 士兵占领
  13. SpringMVC【校验器、统一处理异常、RESTful、拦截器】
  14. UE4 蓝图教程(一) 开始,一个转动的香蕉
  15. 超越网络的JavaScript
  16. SQL Server 2014如何导出数据库
  17. C# OpenCv 证件照换底色
  18. 什么!爬虫要违法了?别慌:守住规则,大胆去爬
  19. 极值点偏移问题的处理策略及探究(作业帮的毕冶老师总结)
  20. 全体起立!广州大学数据库综合设计实验

热门文章

  1. pyecharts基本图表1——Calender(日历图)笔记
  2. 年化费率和年利率的区别
  3. 放大倍数与增益dB换算
  4. 罗马数字表希腊字母表
  5. ajax 实现关键字搜索,jQuery实现搜索页面关键字的功能
  6. Git无法添加文件夹下文件
  7. 我奋斗了18年不是为了和你壹起喝咖啡
  8. (一)论文阅读 | 目标检测之CornerNet
  9. oracle物料单位错误,Oracle EBS 销售时物料保留出错相关症状和处理方法
  10. 以Transaction的生命周期为线索剖析Libra核心组件