Linux下gcc编译器的使用

2020-02-29   204 次阅读


摘要:此为学习Linux课程中关于gcc编译器的一些总结,方便以后查阅。

用集成的编程软件很难了解到程序背后编译器对代码编译过程的具体步骤,所以在这里进行手动编译可以让人更直观的了解到编译器编译代码的过程。

首先,我们来写一段程序,当然是我们最熟悉的它啦!Hello World:

#include <stdio.h>
int main(){
    printf("Hello world!");
    return 0;
}

并保存为test.c

第一种编译方式

然后我们到命令行中输入gcc test.c 直接回车后可以发现多了一个a.out的文件。

a.out就是刚刚生成的可执行文件,现在我们要执行它。

输入./a.out即可执行它了,如下图所示

可以看到我们很顺利的就打印出了Hello world!

总结:

gcc <filename.c>

第二种编译方式

这是一种通过中间代码进行编译

输入gcc -c test.c按下回车,可以看到多了一个以文件名.o命名的文件:

这是编译器用 -c 这个参数时单一生成的中间代码,但是中间代码是不可以执行的,我们需要进行链接生成可执行文件。

输入gcc -o test_1 test.o(其中test_1为你自定义的文件名,test.o为上一步生成的中间文件),我们可以直接执行test_1来看看会得到一样的效果:

总结:

  1. gcc -c <filename.c>
  2. gcc -o <filename_exe> <filename.o>

但是我们在编写代码时不能所以都由自己写,需要用到写好的库文件时,该怎么用呢?

这里我们重新编写代码:

#include <stdio.h>
int main(){
    int ret = 0;
    int data = 100;
    printf("Hello world!\n");
     
    ret = sqrt(data);
    printf("the sqrt = %d\n",ret);

    return 0;
}

如果直接运行gcc -c test.c会发现报错:

可以发现,凡是语法错误在编译的时候就会识别出来了,已经说明函数sqrt未被定义。可以看到解决方案,加上头文件。

#include <stdio.h>
#include <math.h>
int main(){
    int ret = 0;
    int data = 100;
    printf("Hello world!\n");
     
    ret = sqrt(data);
    printf("the sqrt = %d\n",ret);

    return 0;
}

然后编译gcc -c test.cgcc -o test test.o

发现调用别人的函数有两个要求,一是知道函数的原型,一般在头文件中就给出。二是函数会编译成库的形式,我需要来调用这个库的形式,需要告诉调用的库的名字是什么,所以这个问题是因为我们在链接的时候没有把库函数链接上。解决办法:

gcc -o test test.o -lm(链接math.h不是-lmath而是-lm)

这个时候就编译成功了!

输入 man sqrt 可以查看手册,得到链接的参数。

第三种编译方式

测试多个文件怎么进行编译:

这里test.c为主程序,myfunc.c和myfunc.h为模块代码

test.c:

#include <stdio.h>
#include <math.h>
#include "myfunc.h"
int main(){
    int ret = 0;
    int data = 100;
    int a = 0;
    int b = 0;
    printf("Hello world!\n");
     
    ret = sqrt(data);
    printf("the sqrt = %d\n",ret);
    
    a = add(100,200);
    b = sub(1000,200);
    printf("a = %d , b = %d \n",a,b);

    return 0;
}

myfunc.c:

int add(int x, int  y)
{
    return (x+y);
}

int sub (int x, int y)
{
    return (x-y);
}

myfunc.h:

int add(int x,int y);
int sub(int x, int y);

然后使用gcc -c ***各自生成可执行文件,接下来我们将两个中间文件进行链接:

使用gcc -o test test.o myfunc.o -lm进行链接,然后成功执行:

tips:

如果遇到下面这种情况:

是因为本文件夹中查找不到,将头文件中的#include <myfunc.h>改成#include "myfunc.h"即可~

总结:

  1. gcc -c <filename1.c>
  2. gcc -c <filename2.c> ...
  3. gcc -0 <filename_exe> <filename.o> <filename2.o> ...... -l .....

第四种编译方式(makefile)

利用makefile文件来编译程序

test:test.o myfunc.o
	gcc -o test test.o myfunc.o -lm
test.o:test.c
	gcc -c test.c
myfunc.o:myfunc.c
	gcc -c myfunc.c
clean:
	rm *.o

执行

tips:

采用倒叙的方式书写

gcc,rm等命令前加的是TAB (注意不要用空格代替制表符!)

makefile文件格式总结:

<模块名>:<生成所需资源文件>

<生成方法>

gdb调试方法

不能直接使用,需要在编译时加入调试方法

采用的指令是 gcc -g

例如:输入gcc -g test.c myfunc.c -o test -lm也可以正常生成,但是会发现可执行文件容量比较大。

输入gdb test进入调试,界面如下:

查看代码:

  1. list (查看10行的内容)

  2. list 10 (以第10行为中心上下共10行的内容)

  3. list 6,12 (列出6到12行的内容)

输入run可以使得程序在调试时运行

断点设置:

  1. 设置断点 break 行数

  2. 清除断点

    采用info break查看断点信息

    输入 delete breakpoint <Num>即可删除对应编号的断点。

  3. print data 即可查看当前赋的值

  4. 单步运行

    ① step进入函数体的单步执行

    ② next 不进入函数体的单步执行

  5. 多步执行

    step <步数>

    next <步数>


gdb总结:

  1. 生成: gcc -g <源文件> -o <执行文件> -l<库>

  2. 进入调试 gdb <filename_exe>

  3. list 显示十条语句

    list n 以n为中心,显示十条语句

    list m,n 显示从m到n的语句

  4. break <行号> 设断点

  5. info break 显示断点信息

  6. delete breakpoint <编号>

  7. enable/disable breakpoint <编号> 启用/禁用 断点

  8. run 执行到断点

  9. step进入函数体的单步执行

    next 不进入函数体的单步执行

  10. print <变量> 查看变量信息

本文由 hongCYu 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
原文链接:https://hongcyu.cn/posts/linux-gcc.html
最后更新于:2020-12-03 15:25:11

Coffee