Linux的C语言开发工具——通过进度条小程序学习使用gcc、gdb和make/Makefile工具

一、Linux下的进度条程序实现

实现进度条的代码很简单,代码如下

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define NUM 101

int main()
{
    
    
  int i = 0;
  char bar[NUM]; //用于存放进度条数组
  memset(bar, 0, sizeof(bar));
  char label[] = "|/-\\";

  for(i = 0; i < 100; ++i)
  {
    
    
    bar[i] = '#';
    printf("[%-100s][%3d%%][%c]\r", bar, i+1, label[i%4]);
    fflush(stdout);
    usleep(10000);
  }
  printf("\n");
  return 0;
}

最终结果
在这里插入图片描述
想要编译出上面这段代码就需要掌握Linux下基本的开发工具

二、Linux编译器-gcc

一个C语言程序的,需要经过四个步骤:预处理、编译、汇编、链接
gcc是如何完成这四个步骤呢?在LInux下gcc的格式如下:

gcc [选项] 要编译的文件 [选项] [目标文件]

2.1 预处理(进行宏替换)

  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等
  • 预处理指令是以#号开头的代码行。

拿我们的进度条代码举个栗子

gcc -E proc.c -o proc.i

  • 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程
  • 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序

在这里插入图片描述

2.2 编译(生成汇编)

在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言

举个栗子:

gcc -S proc.i -o proc.s

  • 选项“-S”,该选项的作用是让 gcc 在编译后停下来生成汇编语言
  • 选项“-o”是指目标文件,“.s”文件为已经过编译的C原始程序

在这里插入图片描述

2.3 汇编(生成机器可识别代码)

汇编阶段是把编译阶段生成的“.s”文件转成目标文件

举个栗子

gcc -c proc.s -o proc.o

  • 选项==“-c”==就可看到汇编代码已转化为“.o”的二进制目标代码了,可以看到二进制文件如果用普通的打开方式会显示乱码

在这里插入图片描述
用nm命令就可以查看二进制文件了
在这里插入图片描述

2.4 链接(生成可执行文件或库文件)

在成功编译之后,就进入了链接阶段。就可以生成我们想要的执行文件了

举个例子

gcc proc.o -o proc

在这里插入图片描述

2.5 静态库和动态库

  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?

答案是:

系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用

函数库一般分为静态库和动态库两种。

  1. 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。
  2. 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,

2.6 gcc选项

如果熟悉了前面三个选项,通常我们会用.c文件直接生成可执行文件,效果如下

在这里插入图片描述
gcc的其他选项如下

-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S 编译到汇编语言不进行汇编和链接
-c 编译到目标代码
-o 文件输出到 文件
-static 此选项对生成的文件采用静态链接
-g 生成调试信息。GNU 调试器可利用该信息。
-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
-O0
-O1
-O2
-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-w 不生成任何警告信息。
-Wall 生成所有警告信息。

三、Linux调试器-gdb

程序的发布方式有两种,debug模式和release模式
Linux gcc/g++出来的二进制程序,默认是release模式

3.1 gdb调试程序

在这里插入图片描述
要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项
举个栗子

gcc proc.c -o proc-debug -g
在这里插入图片描述

gdb proc-debug #开始调试程序

  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list/l 函数名:列出某个函数的源代码。
  • r或run:运行程序。
  • quit / q:退出gdb。

在这里插入图片描述

3.2 gdb使用断点

break(b) 行号:在某一行设置断点
break 函数名:在某个函数开头设置断点
info break :查看断点信息。
finish:执行到当前函数返回,然后挺下来等待命令
print ( p ) (p) (p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
p 变量:打印变量值。

在这里插入图片描述

delete breakpoints:删除所有断点
delete breakpoints n:删除序号为n的断点
disable breakpoints:禁用断点
enable breakpoints:启用断点
info(或i) breakpoints:参看当前设置了哪些断点
display 变量名:跟踪查看一个变量,每次停下来都显示它的值
undisplay:取消对先前设置的那些变量的跟踪

在这里插入图片描述
在这里插入图片描述

四、Linux项目自动化构建工具-make/Makefile

会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建

4.1 单文件Makefile

首先构建Makefile文件,,如果想要生成可执行文件,完整的过程需要经过四个步骤:预处理、编译、汇编、链接,如下图所示
在这里插入图片描述

  • 依赖关系
    上面的文件 proc ,它依赖 proc.o
    proc.o , 它依赖 proc.s
    proc.s , 它依赖 proc.i
    proc.i , 它依赖 proc.c
  • 依赖方法
    gcc hello.* -option hello.* ,就是与之对应的依赖关系

构建完成后,使用make命令就可以完成单文件程序的构建了,使用make clean就可以完成项目清理
在这里插入图片描述
通常我们用更简单的方式构建单文件工程
在这里插入图片描述
在这里插入图片描述
能生成解决方案,Makefile也提供了项目清理,如下图所示
在这里插入图片描述

清理命令

在这里插入图片描述

4.2 多文件Makefile

我们首先建立多文件proc.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define NUM 101

extern void proc();

proc.h

#include "proc.h"

void proc()
{
    
    
  int i = 0;
  char bar[NUM]; //用于存放进度条数组
  memset(bar, 0, sizeof(bar));
  char label[] = "|/-\\";

  for(i = 0; i < 100; ++i)
  {
    
    
    bar[i] = '#';
    printf("[%-100s][%3d%%][%c]\r", bar, i+1, label[i%4]);
    fflush(stdout);
    usleep(100000);
  }
  printf("\n");
}

main.c

#include "proc.h"

int main()
{
    
    
  proc();
  return 0;
}

我们想要构建多文件工程如下所示,可以一个一个写
在这里插入图片描述
但是如果文件过多,我们会采取下面这种方法
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40076022/article/details/113403676