1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > c++高性能服务器开发01-环境搭建 相关基础概念 Linux系统相关函数

c++高性能服务器开发01-环境搭建 相关基础概念 Linux系统相关函数

时间:2018-09-01 14:25:18

相关推荐

c++高性能服务器开发01-环境搭建 相关基础概念 Linux系统相关函数

1.安装Ubuntu18

openssh-servernet-toolspwdlsvscode 插件:remotec++配置公钥 windows 公钥复制到Linux的./ssh/authorized_keysssh-keygen xshellxpt

2.gcc

安装工作流程 源代码.c .h --预处理器(删除注释 宏处理替换,投文件展开)—处理后源代码.i – 编译器–汇编代码.s(汇编代码)–汇编器–目标代码.o–连接器 --可执行文件.out.exegcc test.c -E -o test.i、gcc test.i -S -o test.sgcc test.s -o test.o

3.g++

类似gcc

g++ test.c -o test

4.gcc和g++的区别

gcc 和 g++都是GNU(组织)的一个编译器。

误区一:gcc

二只能编译c代码,g++只能编译c++代码。两者都可以,请注意:

后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序

后缀为.cpp的,两者都会认为是C++程序,C++的语法规则更加严谨

编译阶段,g++会调用gcc,对于C++代码,两者是等价的,但是因为gcc

命令不能自动和C++程序使用的库联接,所以通常用g++来完成链接,为了统一起见,干脆编译/链接统统用g++了,这就给人一种错觉,好像cpp程序只能用g++似的

误区二:gcc

实际上,这个宏只是标志着编译器将会把代码按C还是C++语法来解释

如上所述,如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则就是已定义

误区三:编译只能用gcc,链接只能用g++

严格来说,这句话不算错误,但是它混淆了概念,应该这样说:编译可以用gcc/g++,而链接可以用g++或者gcc-1stdc++。

gcc命令不能自动和C++程序使用的库联接,所以通常使用g++来完成联接。

但在编译阶段,g++会自动调用gcc,二者等价

5. gcc编译选项

6.静态库制作

库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。

库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

库的好处:1.代码保密2.方便部署和分发

命名规则:

Linux:libxxx.a

lib:前缀(固定)

xxx:库的名字,自己起

.a:后缀(固定)

Windows:libxxx.lib

静态库的制作:

gcc获得.o文件 -c

将.o文件打包,使用ar工具(archive)

ar rcs libxxx.a xxx.o xxx.o

r - 将文件插入备存文件中

C - 建立备存文件

s - 索引

使用

gcc -c add.c sub.c mult.c div.c -I …/include/ 编译生成.oar rcs libcalc.a add.o sub.o mult.o div.o 生成libcal.a静态库文件gcc main.c -o app -I ./include/calc -L ./lib -l calc

7.动态库的制作和使用

命名规则:

Linux:libxxx.so

lib:前缀(固定)

xxx:库的名字,自己起

.so:后缀(固定)

在Linux下是一个可执行文件

Windows:libxxx.dll动态库的制作:

gcc -c 得到.o文件,得到和位置无关的代码

gcc -c -fpic / -fPIC a.c b.c

gcc得到动态库

gcc -shared a.o b.o -o libcalc.so指定头文件目录和动态库文件目录编译得目标文件gcc main.c -o main -I include/ -L lib/ -l calc配置动态库环境变量路径(仅在终端内生效):export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/绝对路径查看环境变量:echo $ LD _ LIBRARY _ PATH查看依赖ldd main用户级环境变量配置: 在家目录下 编辑.bashrc文件source .bashrc 使生效 系统级别环境变量配置 编辑 /etc/profile 文件source .bashrc 使生效 修改/etc/ld.so.cache文件 间接修改 编辑/etc/ld.so.conf将路径直接加入更新 sudo ldconfig 不建议在把库文件放入/lib目录

8.库的工作原理

静态库:GCC进行链接时,会把静态库中代码打包到可执行程序中动态库:GCC进行链接时,动态库的代码不会被打包到可执行程序中程序启动之后,动态库会被动态加载到内存中,通过ldd(list dynamic

dependencies)命令检查动态库依赖关系如何定位共享库文件呢?

当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT_RPATH段 -> 环境变量LD_LIBRARY_PATH —> /etc/ld.so.cache文件列表 —> /lib/, /usr/lib目录找到库文件后将其载入内存。

9.静态库和动态库的对比

1.

静态库

优点:

静态库被打包到应用程序中加载速度快

发布程序无需提供静态库,移植方便缺点:

消耗系统资源,浪费内存

更新、部署、发布麻烦

动态库

优点:

可以实现进程间资源共享(共享库)

更新、部署、发布简单

可以控制何时加载动态库缺点:

加载速度比静态库慢

发布程序时需要提供依赖的动态库

10.makefile

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为Makefile文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。Makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释Makefile文件中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如 Delphi 的 make, Visual C++的 nmake, Linux 下 GNU的make。

命名规则

makefile 或Makefile

makefile规则

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

目标…:依赖…

​ 命令(shell命令)

​ …

目标:最终要生成的文件(伪目标除外)依赖:生成目标所需要的文件或是目标命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)

其他规则为第一规则服务

makefile文件编写

makefile工作原理

工作原理

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

如果存在,执行命令如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令

检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间

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

变量

自定义变量

变量名=变量值 var=hello预定义变量

AR:归档维护程序的名称,默认值为ar

CC:C编译器的名称,默认值为cc

CXX:C++编译器的名称,默认值为g++

$@:目标的完整名称

$<:第一个依赖文件的名称

$^:所有的依赖文件获取变量的值

$(变量名)模式匹配 %.o:%.c

:通配符,匹配一个字符串

-两个%匹配的是同一个字符串%.o:%.c

gcc -c $< -o $@

函数

$(wildcard PATTERN...)//函数名 函数参数

功能:获取指定目录下指定类型的文件列表参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔返回:得到的若干个文件的文件列表,文件名之间使用空格间隔示例:

$(wildcard *.c ./sub/*.c)

返回值格式:a.c b.c c.c d.c e.c f.c

$(patsubst <pattern>,<replacement>,<text>)

功能:查找<text>中的单词(单词以“空格”、“Tab"或“回车”换行“分隔)是否符合模式,如果匹配的话,则以替换。可以包括通配符%,表示任意长度的字串。如果中也包含%,那么,中的这个%将是中的那个%

所代表的字串。(可以用\来转义,以%来表示真实含义的“字符)返回:函数返回被替换过后的字符串示例:

$(patsubst %.c,%.o,x.c bar.c)

返回值格式:x.o bar.o

clean函数

clean:

​ rm $(objs) -f

make clean 不能有clean文件

在之前加.PHONY:clean声明不生成clean文件

11. GDB调试

通常,在为调试而编译时,我们会()关掉编译器的优化选项(-0),并打开调试选项(-g)。另外,——Wa11在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的BUG。

gcc -g -Wall program.c -o program

-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件。

GDB命令

启动和退出

gdb 可执行程序

quit

给程序设置参数/获取设置参数

set args 10 20

show args

GDB使用帮助

help

查看当前文件代码

list/l (从默认位置显示)

list/l 行号(从指定的行显示)

list/l 函数名(从指定的函数显示)

查看非当前文件代码

list/l 文件名:行号

list/l 文件名:函数名

设置显示的行数

show list/listsize

set list/listsize 行数

设置断点

b/break行号

b/break函数名

b/break文件名:行号

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(跳出循环)

12. 标准C库IO函数和Linux系统IO函数对比

13. 虚拟地址空间

14.文件描述符

15. Linux系统IO函数

1. 文件打开关闭open close

int open(const char *pathname, int flags);//文件路径 ,权限,返回文件描述符,失败返回-1

int open(const char *pathname, int flags, mode_t mode);//mode 八进制数:创建的新文件操作权限

int close(int fd);关闭文件

perror,打印错误描述

umask权限掩码 默认0002

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

2. 文件读写read write

ssize_t read(int fd, void *buf, size_t count);//文件描述符,读取数据存放的地方数组地址,数组大小,返回值:读取成功返回读取字节数,失败返回-1

ssize_t write(int fd, const void *buf, size_t count);

/* #include <unistd.h>ssize_t read(int fd, void *buf, size_t count);参数:- fd:文件描述符,open得到的,通过这个文件描述符操作某个文件- buf:需要读取数据存放的地方,数组的地址(传出参数)- count:指定的数组的大小返回值:- 成功:>0: 返回实际的读取到的字节数=0:文件已经读取完了- 失败:-1 ,并且设置errno#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);参数:- fd:文件描述符,open得到的,通过这个文件描述符操作某个文件- buf:要往磁盘写入的数据,数据- count:要写的数据的实际的大小返回值:成功:实际写入的字节数失败:返回-1,并设置errno*/#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main() {// 1.通过open打开english.txt文件int srcfd = open("english.txt", O_RDONLY);if(srcfd == -1) {perror("open");return -1;}// 2.创建一个新的文件(拷贝文件)int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);if(destfd == -1) {perror("open");return -1;}// 3.频繁的读写操作char buf[1024] = {0};int len = 0;while((len = read(srcfd, buf, sizeof(buf))) > 0) {write(destfd, buf, len);}// 4.关闭文件close(destfd);close(srcfd);return 0;}

3. 文件指针偏移fseek

off_t lseek(int fd, off_t offset, int whence);

/* 标准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得到的,通过这个fd操作某个文件- offset:偏移量- whence:SEEK_SET设置文件指针的偏移量SEEK_CUR设置偏移量:当前位置 + 第二个参数offset的值SEEK_END设置偏移量:文件大小 + 第二个参数offset的值返回值:返回文件指针的位置 作用:1.移动文件指针到文件头lseek(fd, 0, SEEK_SET);2.获取当前文件指针的位置lseek(fd, 0, SEEK_CUR);3.获取文件长度lseek(fd, 0, SEEK_END);4.拓展文件的长度,当前文件10b, 110b, 增加了100个字节lseek(fd, 100, SEEK_END)注意:需要写一次数据*/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>int main() {int fd = open("hello.txt", O_RDWR);if(fd == -1) {perror("open");return -1;}// 扩展文件的长度int ret = lseek(fd, 100, SEEK_END);if(ret == -1) {perror("lseek");return -1;}// 写入一个空数据write(fd, " ", 1);// 关闭文件close(fd);return 0;}

4. 获取文件相关的信息stat

int stat ( const char * pathname , struct stat * statbuf ) ;

int lstat ( const char * pathname , struct stat * statbuf ) ;

/*#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>int stat(const char *pathname, struct stat *statbuf);作用:获取一个文件相关的一些信息参数:- pathname:操作的文件的路径- statbuf:结构体变量,传出参数,用于保存获取到的文件的信息文件大小 块 类型 设备 权限 Inode 硬链接 Uid Gid 时间戳返回值:成功:返回0失败:返回-1 设置errnoint lstat(const char *pathname, struct stat *statbuf);//获取软链接信息参数:- pathname:操作的文件的路径- statbuf:结构体变量,传出参数,用于保存获取到的文件的信息返回值:成功:返回0失败:返回-1 设置errnostruct stat {dev_t st_dev;//文件的设备编号ino_t st_ino;//节点mode_t st mode;//文件的类型和存取的权限nlink_t st_nlink;//连到该文件的硬连接数目uid_t st_uid; //用户IDgid_t st_gid;//组IDdev_t st_rdev;//设备文件的设备编号off_t st_size;//文件字节数(文件大小)blksize_t st_blksize;//块大小blkcnt_t st_blocks;//块数time_t st_atime;//最后一次访问时间time_t st_mtime;//最后一次修改时间time_t st_ctime; //最后一次改变时间(指属性)};*/#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdio.h>int main() {struct stat statbuf;int ret = stat("a.txt", &statbuf);if(ret == -1) {perror("stat");return -1;}printf("size: %ld\n", statbuf.st_size);return 0;}

//案例#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <pwd.h>#include <grp.h>#include <time.h>#include <string.h>// 模拟实现 ls -l 指令// -rw-rw-r-- 1 nowcoder nowcoder 12 12月 3 15:48 a.txtint main(int argc, char * argv[]) {// 判断输入的参数是否正确if(argc < 2) {printf("%s filename\n", argv[0]);return -1;}// 通过stat函数获取用户传入的文件的信息struct stat st;int ret = stat(argv[1], &st);if(ret == -1) {perror("stat");return -1;}// 获取文件类型和文件权限char perms[11] = {0}; // 用于保存文件类型和文件权限的字符串switch(st.st_mode & S_IFMT) {case S_IFLNK:perms[0] = 'l';break;case S_IFDIR:perms[0] = 'd';break;case S_IFREG:perms[0] = '-';break; case S_IFBLK:perms[0] = 'b';break; case S_IFCHR:perms[0] = 'c';break; case S_IFSOCK:perms[0] = 's';break;case S_IFIFO:perms[0] = 'p';break;default:perms[0] = '?';break;}// 判断文件的访问权限// 文件所有者perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';// 文件所在组perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';// 其他人perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';// 硬连接数int linkNum = st.st_nlink;// 文件所有者char * fileUser = getpwuid(st.st_uid)->pw_name;// 文件所在组char * fileGrp = getgrgid(st.st_gid)->gr_name;// 文件大小long int fileSize = st.st_size;// 获取修改的时间char * time = ctime(&st.st_mtime);char mtime[512] = {0};strncpy(mtime, time, strlen(time) - 1);char buf[1024];sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);printf("%s\n", buf);return 0;}

4. 文件属性操作函数

int access (const char *pathname, int mode);//判断权限

int chmod(const char*filename,int mode);//修改权限

int chown(const char*path,uid_t owner,gid_t group);//设置文件所有者

int truncate(const char*path,off_t length);//扩展文件

/*#include <unistd.h>int access(const char *pathname, int mode);作用:判断某个文件是否有某个权限,或者判断文件是否存在参数:- pathname: 判断的文件路径- mode:R_OK: 判断是否有读权限W_OK: 判断是否有写权限X_OK: 判断是否有执行权限F_OK: 判断文件是否存在返回值:成功返回0, 失败返回-1*/#include <unistd.h>#include <stdio.h>int main() {int ret = access("a.txt", F_OK);if(ret == -1) {perror("access");}printf("文件存在!!!\n");return 0;}///

/*#include <sys/stat.h>int chmod(const char *pathname, mode_t mode);修改文件的权限参数:- pathname: 需要修改的文件的路径- mode:需要修改的权限值,八进制的数返回值:成功返回0,失败返回-1*/#include <sys/stat.h>#include <stdio.h>int main() {int ret = chmod("a.txt", 0777);if(ret == -1) {perror("chmod");return -1;}return 0;}

/*#include <unistd.h>#include <sys/types.h>int truncate(const char *path, off_t length);作用:缩减或者扩展文件的尺寸至指定的大小参数:- path: 需要修改的文件的路径- length: 需要最终文件变成的大小返回值:成功返回0, 失败返回-1*/#include <unistd.h>#include <sys/types.h>#include <stdio.h>int main() {int ret = truncate("b.txt", 5);if(ret == -1) {perror("truncate");return -1;}return 0;}

5. 目录操作函数

int mkdir (const char *pathname, mode_t mode);//创建目录

int rmdir(const char *pathname);//删除

int rename(const char*oldpath,const char*newpath);//修改name

int chdir(const char *path);//切换到目录

char*getcwd(char*buf,size_t size);//获取绝对路径buf以及空间大小。

/*#include <sys/stat.h>#include <sys/types.h>int mkdir(const char *pathname, mode_t mode);作用:创建一个目录参数:pathname: 创建的目录的路径mode: 权限,八进制的数返回值:成功返回0, 失败返回-1*/#include <sys/stat.h>#include <sys/types.h>#include <stdio.h>int main() {int ret = mkdir("aaa", 0777);if(ret == -1) {perror("mkdir");return -1;}return 0;}

////*#include <stdio.h>int rename(const char *oldpath, const char *newpath);*/#include <stdio.h>int main() {int ret = rename("aaa", "bbb");if(ret == -1) {perror("rename");return -1;}return 0;}//

/*#include <unistd.h>int chdir(const char *path);作用:修改进程的工作目录比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder参数:path : 需要修改的工作目录#include <unistd.h>char *getcwd(char *buf, size_t size);作用:获取当前工作目录参数:- buf : 存储的路径,指向的是一个数组(传出参数)- size: 数组的大小返回值:返回的指向的一块内存,这个数据就是第一个参数*/#include <unistd.h>#include <stdio.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>int main() {// 获取当前的工作目录char buf[128];getcwd(buf, sizeof(buf));printf("当前的工作目录是:%s\n", buf);// 修改工作目录int ret = chdir("/home/nowcoder/Linux/lesson13");if(ret == -1) {perror("chdir");return -1;} // 创建一个新的文件int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);if(fd == -1) {perror("open");return -1;}close(fd);// 获取当前的工作目录char buf1[128];getcwd(buf1, sizeof(buf1));printf("当前的工作目录是:%s\n", buf1);return 0;}

6. 目录遍历函数

DIR *opendir (const char *name);

struct dirent *readdir (DIR *dirp);

int closedir (DIR *dirp);

/*// 打开一个目录#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);参数:- name: 需要打开的目录的名称返回值:DIR * 类型,理解为目录流错误返回NULL// 读取目录中的数据#include <dirent.h>struct dirent *readdir(DIR *dirp);- 参数:dirp是opendir返回的结果- 返回值:struct dirent,代表读取到的文件的信息读取到了末尾或者失败了,返回NULLstruct dirent{//此目录进入点的inodeino_t d ino;//目录文件开头至此目录进入点的位移off_t d_off;//d_name的长度,不包含NULL字符unsigned short int d_reclen;//d_name所指的文件类型unsigned char d_type;//文件名char d_name[256];};文件类型d typeDT_BLK-块设备DT_CHR-字符设备DT_DIR-目录DT_LNK-软连接DT_FIFO-管道DT_REG-普通文件DT_SOCK-套接字DT_UNKNOWN-未知​// 关闭目录#include <sys/types.h>#include <dirent.h>int closedir(DIR *dirp);*/#include <sys/types.h>#include <dirent.h>#include <stdio.h>#include <string.h>#include <stdlib.h>​ int getFileNum(const char * path); // 读取某个目录下所有的普通文件的个数int main(int argc, char * argv[]) {​ ​ if(argc < 2) {printf("%s path\n", argv[0]);return -1;}​int num = getFileNum(argv[1]);printf("普通文件的个数为:%d\n", num);​return 0;}​ // 用于获取目录下所有普通文件的个数int getFileNum(const char * path) {// 1.打开目录DIR * dir = opendir(path);if(dir == NULL) {perror("opendir");exit(0);}​ struct dirent *ptr;​// 记录普通文件的个数​ int total = 0;​ while((ptr = readdir(dir)) != NULL) {​ // 获取名称​char * dname = ptr->d_name;// 忽略掉. 和..if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {continue;}// 判断是否是普通文件还是目录if(ptr->d_type == DT_DIR) {// 目录,需要继续读取这个目录char newpath[256];sprintf(newpath, "%s/%s", path, dname);total += getFileNum(newpath);}if(ptr->d_type == DT_REG) {// 普通文件total++;}}// 关闭目录closedir(dir);return total;}

7.复制文件描述符 dup dup2

int dup (int oldfd) ;复制文件描述符

int dup2(int oldfd, int newfd);重定向文件描述符

/*#include <unistd.h>int dup(int oldfd);作用:复制一个新的文件描述符fd=3, int fd1 = dup(fd),fd指向的是a.txt, fd1也是指向a.txt从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符*/#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>int main() {int fd = open("a.txt", O_RDWR | O_CREAT, 0664);int fd1 = dup(fd);if(fd1 == -1) {perror("dup");return -1;}printf("fd : %d , fd1 : %d\n", fd, fd1);close(fd);char * str = "hello,world";int ret = write(fd1, str, strlen(str));if(ret == -1) {perror("write");return -1;}close(fd1);return 0;}

///*#include <unistd.h>int dup2(int oldfd, int newfd);作用:重定向文件描述符oldfd 指向 a.txt, newfd 指向 b.txt调用函数成功后:n ewfd 和 b.txt 做close, newfd 指向了 a.txtoldfd 必须是一个有效的文件描述符oldfd和newfd值相同,相当于什么都没有做*/#include <unistd.h>#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.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(fd1 == -1) {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(fd);close(fd1);return 0;}

8. fcntl文件描述符操作

int fcntl (int fd, int cmd, ... /* arg */ );

复制文件描述符

设置/获取文件的状态标志

/*#include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, ...);参数:fd : 表示需要操作的文件描述符cmd: 表示对文件描述符进行如何操作- F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)int ret = fcntl(fd, F_DUPFD);- F_GETFL : 获取指定的文件描述符文件状态flag获取的flag和我们通过open函数传递的flag是一个东西。- F_SETFL : 设置文件描述符文件状态flag必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改可选性:O_APPEND, O_NONBLOCKO_APPEND 表示追加数据O_NONBLOCK 设置成非阻塞阻塞和非阻塞:描述的是函数调用的行为。*/#include <unistd.h>#include <fcntl.h>#include <stdio.h>#include <string.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(fd == -1) {perror("open");return -1;}// 获取文件描述符状态flagint flag = fcntl(fd, F_GETFL);if(flag == -1) {perror("fcntl");return -1;}flag |= O_APPEND; // flag = flag | O_APPEND// 修改文件描述符状态的flag,给flag加入O_APPEND这个标记int ret = fcntl(fd, F_SETFL, flag);if(ret == -1) {perror("fcntl");return -1;}char * str = "nihao";write(fd, str, strlen(str));close(fd);return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。