Linux下的C语言开发学习笔记

个人GitHub代码链接:https://github.com/NAMZseng/C-Practice-Under-Linux


gcc编译四个过程

  • 预处理

    • 头文件包含、宏替换、条件编译、删除注释

    • gcc -E

    • 该步骤生成的文件后缀 .i

  • 编译

    • 语法检查、将预处理的文件编译成汇编文件

    • gcc -S

    • 该步骤生成的文件后缀 .s

  • 汇编

    • 将汇编文件处理成二进制文件

    • gcc -c

    • 该步骤生成的文件后缀 .o

  • 链接

    • 整合二进制文件、相关库函数、启动代码生成可执行文件,main函数是由启动代码调用的,程序是从启动代码开始运行的。

    • 静态链接,指调用ld/collect2链接程序,将所有的.o中的机器指令整合到一起,然后保存到可执行文件中。

    • 动态链接,在编译的时候只留下调用接口(函数第一条指令的地址),当程序真正运行的时候,才去链接执行,动态链接这件事不是在编译时发生的,是在程序动态运行时发生。

    • 比如程序中调用printf函数,这个函数基本都是动态库提供的,程序编译后代码里面是没有printf函数代码的,只有printf这个接口,当程序运行起来后,再去动态链接printf所在的动态库,那么程序就能调用printf函数。

    • Linux默认的动态库搜索路径/usr/lib

    • gcc

    • 该步骤生成的文件后缀 .out

    参考自

动态空间的申请与释放

 //动态从堆区空间申请
 int *p = (int *)malloc(n*sizeof(int)); 
 if(p == NULL) 
 {
  perror("malloc"); 
  exit(-1);
 }
 // 空间的释放
 if(p != NULL)
 {
  // 释放指向的内存空间
  free(p);
  // 取消对以释放空间的指向
  p = NULL;
 }

进程相关

进程创建

  • 进程是系统资源分配的最小单位,是正在运行的,且占有内存空间。

  • Linux环境中创建进程可通过调用fork() / vfork()函数,在一个已经存在的进程中创建一个新的子进程,它拷贝了父进程的地址空间,包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等,子进程仅独有其进程号、计时器等,因此使用fork()创建的进程的代价是较大的。

  • 父子进程的地址空间相同,但相互独立。

  • 子进程从fork()语句后开始执行。

  • 但在进程中使用exec函数族时,exec中调用执行的程序会替换当前进程。

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

   ...

   pid_t pid = fork();
   if(pid < 0) // 创建失败
   {
       perror("fork");
       _exit(-1);
   }
   if(pid == 0) // 子进程
   {
      ...
   }
   else if (pid > 0) // 父进程,返回的pid是子进程的id
   {
      ...
   }

进程通信——管道

  • 管道是内核提供的一段内存(队列),这段内存抽象成文件,通过访问文件描述符的形式,来读写这块内存中的数据。

  • 单向通信,半双工

  • 面向字节流

  • 内置同步互斥机制。互斥:当多个进程一起读时会,读到完整数据或者读不到数据。同步:管道为空,读阻塞;管道满了,写阻塞。

  • 所有引用这个管道的进程都销毁,管道才释放。真正释放的只是管道在内核中对应的这段内存,这个内存才是管道的本质

  • 无名管道

    • 仅限于具有“血缘关系”的进程间(如父子进程)的通信,因为这类进程在创建时拷贝了父进程的地址空间,其中包含了以打开的文件描述符,故可以打开以在父进程中创建的无名管道,进行相互通信。
  // 创建数组存储管道的文件描述符,fd[0]用于读, fd[1]用于写
   int fd[2];
   // 创建并打开管道
   pipe(fd);

   pid_t pid = fork();

   if(pid == 0) 
   {
   // 可在子进程中读取管道信息
   char buf[128] = "";
   read(fd[0], buf, sizeof(buf));
   }
   if(pid > 0)
   {
   // 可在父进程中向管道写信息
   write(fd[1], "hello pipe", strlen("hello pipe"));
   }
  • 命名管道

    • 相互通信的进程可通过管道的名字(即文件名),打开管道进行读/写

    • 一般在读端与写端都分别创建同一命名管道(当要创建文件存在时,文件不会重复再创建),因为无法确定实际运行中,哪端的代码先运行。若仅在一端创建管道文件,而是另一端先运行到open管道文件的代码时,会因找不到该文件而报错。通过读写两端分别创建同一命名管道文件,可以确保无论哪端先执行到open代码,都能正常打开管道。

    • 读端进程

       // 创建一个有名管道,并赋予相关权限
        mkfifo("fifo_demo", 0777);
      
        // 以只读的方式打开创建的有名管道
        int fd = open("fifo_demo", O_RDONLY);
      
        char buf[128] = "";
        read(fd, buf, sizeof(buf));
        printf("读取到的数据为:%s\n", buf);
      
        // 关闭文件描述符fd
        close(fd);
      
    • 写端进程

       // 创建一个有名管道
       mkfifo("fifo_demo", 0777);
    
       // 以只写的方式打开创建的有名管道
       int fd = open("fifo_demo", O_WRONLY);
    
       // 发送消息
       write(fd, "hello fifo", strlen("hello fifo"));
    
       // 关闭文件描述符fd
       close(fd);
    
    • 文件描述符符重定向
       if(pid == 0) // 子进程
        {
         // 由于grep仅从输入设备0中读取信息
         // 所以需要将文件描述符1重定向到fd[0],使grep从无名管道中读取结果
         dup2(fd[0], 0);
        ​
         // 执行grep命令
         execlp("grep", "grep", "ps", NULL);
        }
        else if (pid > 0) // 父进程
        {
         // 由于ps仅向输出设备1中写结果
         // 所以需要将文件描述符1重定向到fd[1],使ps向无名管道中输出结果
         dup2(fd[1], 1);
        ​
         // 执行ps命令
         execlp("ps", "ps", "-elf", NULL);
        }
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容

  • ### main函数执行之前做了什么?(iOS) & dyld 是Apple 的动态链接器;在 xnu 内核为程...
    天使君阅读 684评论 0 1
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • 信号信号是linux操作系统进程间通信的一种方式,一个应用进程可以接受、发送信号给另一个进程,当进程捕获到某个信号...
    zhile_doing阅读 465评论 0 0
  • 1. 硬链接和软连接区别 硬连接-------指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区...
    杰伦哎呦哎呦阅读 2,244评论 0 2
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,791评论 0 27