1.Linux系统编程入门

本文详细介绍了GCC编译器的功能及其工作流程,包括静态库与动态库的制作与使用,并对比了GCC与G++的区别。此外,还深入解析了Linux系统中的IO函数,如open、read、write等,并提供了多个实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1配置环境

Xshell、Xftp、vmware16、Ubuntu18、Visual Studio Code

1.2GCC

1.什么是GCC?

◼ GCC 原名为 GNU C语言编译器(GNU C Compiler)

◼ GCC(GNU Compiler Collection,GNU编译器套件)是由GNU 开发的编程语言 译器。GNU 编译器套件包括 C、C++、Objective-C、Java、Ada 和 Go 语言前 端,也包括了这些语言的库(如 libstdc++,libgcj等)

◼ GCC 不仅支持 C 的许多“方言”,也可以区别不同的 C 语言标准;可以使用命令行选项来控制编译器在翻译源代码时应该遵循哪个 C 标准。例如,当使用命令行参数 `-std=c99` 启动 GCC 时,编译器支持 C99 标准。

◼ 安装命令 sudo apt install gcc g++ (版本 > 4.8.5)

◼ 查看版本 gcc/g++ -v/--version

2.编程语言的发展

3.GCC工作流程

 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 不会定义 __cplusplus 宏,而 g++ 会

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

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

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

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

 gcc 命令不能自动和C++程序使用的库联接,所以通常使用 g++ 来完成联接。 但在编译阶段,g++ 会自动调用 gcc,二者等价

5.GCC常用参数选项

 1.3静态库的制作和使用

1.什么是库

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

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

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

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

2.静态库的制作

3.静态库的使用

举例:

 cd calc

编译、汇编,得到 .o文件

gcc -c add.c div.c mult.c sub.c

制作静态库

ar rcs libcalc.a add.o div.o mult.o sub.o //libcalc.a---库文件名 calc---库的名称

 把库文件拷贝到library/lib目录下

cp libcalc.a ../library/lib

进入library目录编译main.c源文件

cd library

gcc main.c -o main -I ./include -L ./lib -l calc

 1.4动态库的制作和使用

1.动态库的制作

制作动态库:

 cd calc

gcc -c -fpic add.c sub.c mult.c div.c

gcc -shared add.o sub.o mult.o div.o -o libcalc.so

 cp libcalc.so ../library/lib

cd library

gcc main.c -o main -I ./include -L ./lib -l calc

2.工作原理

◼ 静态库:GCC 进行链接时,会把静态库中代码打包到可执行程序中

◼ 动态库:GCC 进行链接时,动态库的代码不会被打包到可执行程序中

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

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

【解决动态库加载失败问题】

方法一环境变量 LD_LIBRARY_PATH         //缺点:一次性配置,终端关闭后即失效。

(1)export +环境变量=$环境变量:动态库路径

第一步:终端窗口输入

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/xiong/Linux/lession06/library/lib

回车

可用echo指令查看环境变量的路径

echo $LD_LIBRARY_PATH

第二步:

ldd main(可执行文件)

//(2)、(3)为永久性配置

(2)用户级别的配置:

cd 进入home目录下

vim .bashrc----回车

shift+g进入到最后一行

插入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/xiong/Linux/lession06/library/lib

保存

更新 . .bashrc-----使保存生效。或者使用 source .bashrc

(3)系统级别配置:

sudo vim /etc/profile-----回车

shift+g进入到最后一行

插入

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/xiong/Linux/lession06/library/lib

保存

更新 source /etc/profile

方法二: /etc/ld.so.cache文件列表

vim /etc/ld.so.cache ---看不懂的乱码文件

间接修改--sudo vim /etc/ld.so.conf

添加动态库路径 /home/xiong/Linux/lession06/library/lib

更新---sudo ldconfig

1.5静态库和动态库的对比

1.程序编译成可执行程序的过程

 2.静态库制作过程

 3.动态库制作过程

 4.静态库的优缺点

1.6Makefile

1.什么是Makefile

 2.Makefile 文件命名和规则

 3.工作原理

 4.变量

 例子:

app:sub.o add.o mult.o div.o main.o
        gcc sub.o add.o mult.o div.o main.o -o app
----------------用变量替换----------------------------------
#定义变量   //vim中是注释是用#
src=sub.o add.o mult.o div.o main.o
target=app
$(target):$(src)
        $(CC) $(src) -o $(target)

5.模式匹配

 6.函数

 1.7GDB调试

1.什么是GDB

 2.准备工作

 3.GDB 命令 – 启动、退出、查看代码

 4.GDB 命令 – 断点操作

 5.GDB 命令 – 调试命令

 1.8标准c库IO函数和Linux系统IO函数对比

1.标准 C 库 IO 函数

 2.标准 C 库 IO 和 Linux 系统 IO 的关系

 3.虚拟地址空间

 4.文件描述符

 5.Linux 系统 IO 函数

◼ int open(const char *pathname, int flags);

◼ int open(const char *pathname, int flags, mode_t mode);

◼ int close(int fd);

◼ ssize_t read(int fd, void *buf, size_t count);

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

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

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

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

---------------------------------------------------------------------------------------------------------------------------------

【open打开文件】

/*
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
#include <unistd.h>
//打开一个已经存在的文件
int open(const char *pathname, int flags);
参数:
    -pathname:要打开的文件路径;
    -flags:对文件的操作权限设置,以及其他的设置;
    O_RDONLY, O_WRONLY, O_RDWR 这三个设置是互斥的
    返回值:返回一个新的文件描述符,如果调用失败,返回-1

errno:属于Linux系统函数库,是库里面的一个全局变量,记录的是最近的错误号。

perror:
#include <stdio.h>
void perror(const char *s);作用:打印error对应的错误描述
    s参数:用户描述,比如hello,最终输出的内容是 hello:xxx(实际的错误描述)
*/
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include<stdio.h>
 #include <unistd.h>
 int main()
 {
     int fd=open("a.txt",O_RDONLY);
     if(fd==-1)
     {
         perror("open");
     }
     //关闭
     close(fd);
     return 0;
 }

【open创建新文件】

/*
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
//创建一个新的文件
int open(const char *pathname, int flags, mode_t mode);
    参数:
        -pathname:要创建文件的路径;
        flags:对文件的操作权限和其他的设置
         -必选项:O_RDONLY, O_WRONLY, O_RDWR 这三个之间是互斥的
         -可选项:O_CREAT文件不存在,创建新文件
    -mode:八进制的数,表示创建出的新的文件的操作权限,比如:0775
    最终的权限是:mode &  ~umask
    ------当前终端umask为0002,~umask为0775------
    0777   ->  111111111
    0775   ->  111111101
    ----------------------
               111111101
    按位与:0和任何数都为0
    umask的作用就是抹去某些权限。

    flags参数是一个int类型的数据,占4个字节,32位;
    flags 32位,每一位是一个标志位。
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
int main()
{
    //创建一个新文件
    int fd=open("create.txt",O_RDWR|O_CREAT,0777);
    if(fd==-1)
    {
        perror("open");
    }
    //关闭
    close(fd);
    return 0;
}

【read、write函数】

 /*
    ----------------------read------------------------------
    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
        参数:
        -fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
        -buf:需要读取数据存放的地方,数组的地址(传出参数)
        -count:指定的数组的大小

    返回值:
        -成功:
            >0:返回实际的读取到的字节数
            =0:文件已经读取完了
        -失败:-1,并且设置errno
    ----------------------write------------------------------
    #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;
    }

【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得到的,通过这个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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.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;
}

【stat/lstat函数】

/*
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
    作用:获取一个文件相关的一些信息
    参数:
      -pathname:操作的文件的路径
      -statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
        成功:返回0
        失败:返回-1 设置errno
int lstat(const char *pathname, struct stat *statbuf);
作用:获取软链接文件信息
参数:
      -pathname:操作的文件的路径
      -statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
        成功:返回0
        失败:返回-1 设置errno
*/
#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;
}

 【模拟实现ls -l命令】

//模拟实现  ls -l 指令
//-rw-rw-r-- 1 xiong xiong   12 12月  6 10:32  a.txt

#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>
int 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;
}

 【文件属性操作函数】

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

 【mkdir】

/*
  #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;
}

【rename】

/*
#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;
}

【chdir/getcwd函数】

/*
 #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/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
    //获取当前的工作目录
    char buf[128];
    getcwd(buf,sizeof(buf));
    printf("当前的工作目录是:%s\n",buf);

    //修改工作目录
    int ret=chdir("/home/xiong/Linux/lession13");
    if(ret==-1)
    {
        perror("chdir");
        return -1;
    }
    //创建一个新的文件
    int fd=open("chdir.txt",O_CREAT|O_RDWR,0664);
    if(fd==-1)
    {
        perror("chdir");
        return -1;
    }
    //关闭文件
    close(fd);

    //获取当前的工作目录
    char buf1[128];
    getcwd(buf1,sizeof(buf1));
    printf("当前的工作目录是:%s\n",buf1);
    return 0;
}

 【opendir/readdir/closedir函数】

/*
//打开一个目录
 #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返回的结果
    读取到了末尾或者失败了,返回NULL

//关闭目录
#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)
{
    //打开目录
    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;
        }
        //判断是否是普通文件or目录
        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;
}

 【dup函数】

/*
---------dup------------
#include <unistd.h>
int dup(int oldfd);
    作用:复制一个新的文件描述符
    fd=3,int fd1=dup(fd)
    fd指向的是a.txt,fd1也是指向a.txt
从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.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;
}

【dup2函数】

/*
#include <unistd.h>
int dup2(int oldfd, int newfd);
    作用:重定向文件描述符
    oldfd指向a.txt,newfd指向b.txt
    调用函数成功后:newfd和b.txt做close,newfd指向a.txt
    oldfd必须是一个有效的文件描述符
    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.txt
    char * 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;
}

【fcntl函数】 

 /*
#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_NONBLOCK
            O_APPEND表示追加数据
            O_NONBLOCK设置成非阻塞
阻塞和非阻塞:描述的是函数调用的行为。             
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main()
{
    //1.复制文件描述符
    //int fd=open("1.txt",O_RDWR);
    //int ret=fcntl(fd,F_DUPFD);

    //2.修改或者获取文件状态flag
    //自行创建一个文件1.txt,已写入字符hello
    int fd=open("1.txt",O_RDWR);
    if(fd==-1)
    {
        perror("open");
        return -1;
    }

    //获取文件描述符状态flag
    int 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=",world";
    //追加完以后1.txt里面的内容为---hello,world
    write(fd,str,strlen(str));
    close(fd);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值