【 gcc & gdb】

1.什么是gcc

gcc是GNU编译器(GNU Compiler Collection)的简称,它是一款支持多种编程语言的编译器,包括C、C++、Objective-C、Fortran、Ada等。

1.1.gcc所遵循的部分约定规则

gcc通过后缀来区别输入文件的类别,下面我们来介绍gcc所遵循的部分约定规则。
.c为后缀的文件,表示C语言源文件;
.C或.cc或.cxx为后缀的文件,表示C++源文件;
.h为后缀的文件,表示程序所包含的头文件;
.s为后缀的文件,表示汇编语言源文件;
.S为后缀的文件,表示经过预处理的汇编语言源文件;
.m为后缀的文件,表示Objective-C源文件;
.i为后缀的文件,表示已经预处理过的C源文件;
.ii为后缀的文件,表示已经预处理过的C++源文件;
.o为后缀的文件,表示编译后的目标文件;
.so为后缀的文件,表示共享库文件;
.a为后缀的文件,表示静态库文件;
.bat为后缀的文件,表示批处理文件;
.sh为后缀的文件,表示shell脚本文件;
.exe为后缀的文件,表示可执行文件;
.out为后缀的文件,表示特殊的可执行文件,通常作为gcc编译器或者汇编器等工具的默认输出文件格式。

1.2.gcc的执行过程

虽然我们称gcc是C语言的编译器,但使用gcc由C语言源代码文件生成可执行文件的过程不仅仅是编译的过程,而是要经历四个相互关联的步骤∶预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)。

在预处理阶段,编译器会对源代码进行处理,包括头文件的包含、宏定义的展开、条件编译等操作。其结果是一个被处理过的源代码文件。
在编译阶段,编译器将被预处理过的源代码文件翻译成汇编代码,也就是将高级语言翻译成汇编语言,生成名为目标代码的文件。
在汇编阶段,汇编器将目标代码翻译成可重定位目标文件,这些文件包含机器代码和指令标号等信息,但是它们还不是完整的可执行文件。
在链接阶段,链接器将多个可重定位目标文件(包括库文件)合并成一个单独的可执行文件,同时解析符号引用,进行地址重定向,生成可执行文件。

2.gcc的基本用法和选项

在使用gcc编译器的时候,我们必须给出一系列必要的调用参数和文件名称。gcc编译器的调用参数大约有100多个,其中多数参数我们可能根本就用不到,这里只介绍其中最基本、最常用的参数
gcc最基本的用法是∶gcc [options] [filenames] ,其中options就是编译器所需要的参数,filenames给出相关的文件名称。

3.编译过程的gcc命令

gcc是gnu下的c编译器

$ sudo apt install gcc #安装gcc
$ gcc -v               #查看gcc的版本

下图是生成可执行程序的整个过程:

在这里插入图片描述
对应的 gcc 命令如下:

$ gcc -E main.c -o main.i # 预处理,从.c到.i
$ gcc -S main.i -o main.s # 编译,从.i到.s
$ gcc -c main.s -o main.o # 汇编,从.s到.o
$ gcc main.o -o main      # 链接,从.o到.out(linux) 或者 .exe(windows)

也可以直接

$ gcc main.c -o main #直接生成可执行程序 main,不指定可执行程序名字则默认生成 a.out

4.gcc命令其他选项

4.1 -Wall

-Wall 生成所有警告信息

例子:一个很多错误的main.c文件:

   1 
    2 int main()
    3 { 
    4     int a;
    5     a=10;6     b=20;7     30/0;8     c                                                                                   
    9     printf("Hello world\n");
   10     return 0;
   11 }
   12  
  ~                

不使用-Wall选项显示如下:

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main
main.c: In function ‘main’:
main.c:6:5: error: ‘b’ undeclared (first use in this function)
     b=20;
     ^
main.c:6:5: note: each undeclared identifier is reported only once for each function it appears in
main.c:7:7: warning: division by zero [-Wdiv-by-zero]
     30/0;
       ^
main.c:8:5: error: unknown type name ‘c’
     c
     ^
main.c:9:12: error: expected declaration specifiers or ‘...’ before string constant
     printf("Hello world\n");
            ^~~~~~~~~~~~~~~

使用-Wall选项显示如下:

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main -Wall
main.c: In function ‘main’:
main.c:6:5: error: ‘b’ undeclared (first use in this function)
     b=20;
     ^
main.c:6:5: note: each undeclared identifier is reported only once for each function it appears in
main.c:7:7: warning: division by zero [-Wdiv-by-zero]
     30/0;
       ^
main.c:7:7: warning: statement with no effect [-Wunused-value]
     30/0;
     ~~^~
main.c:8:5: error: unknown type name ‘c’
     c
     ^
main.c:9:12: error: expected declaration specifiers or ‘...’ before string constant
     printf("Hello world\n");
            ^~~~~~~~~~~~~~~
main.c:4:9: warning: variable ‘a’ set but not used [-Wunused-but-set-variable]
     int a;
         ^

结论:使用-Wall选项会显示更多错误信息

4.2 -D

-D N 相当于在文件开头写 #define N
-D PI=3.14 相当于在文件开头写 #define PI 3.14

例子:main.c

  1 #include<stdio.h>
  2 
  3 int main(){
  4 #ifdef N   //如果N被define了,就执行ifdef与endif之间的语句
  5     printf("%d\n",N);                                                                     
  6 #endif
  7     return 0;
  8 }

不用-D

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main
liuwendong@liuwendong-virtual-machine:~/2023_5_27$ ./main

使用-D

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main -D N=10
liuwendong@liuwendong-virtual-machine:~/2023_5_27$ ./main
10

4.3 -I(大写i)

对于 #include “head.h”,gcc会先在当前目录查找你所指定的头文件,如果没有找到,它会到系统的 include 目录寻找
如果使用 -I 指定了目录,它会先在你所指定的目录查找,然后再按常规的顺序去找

-I /home/liuwendong/dir1 先去/home/liuwendong/dir1下寻找头文件

例子:main.c

    1 #include"head.h"                                                                        
    2 
    3 int main(){4     printf("I love you!\n");
    5     return 0;
    6 }           

不使用-I

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main
main.c:1:9: fatal error: head.h: 没有那个文件或目录
 #include"head.h"
         ^~~~~~~~
compilation terminated.

使用-I

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main -I /home/liuwendong/dir1liuwendong@liuwendong-virtual-machine:~/2023_5_27$ ./main
I love you!

4.4 -g

-g 指示编译器在编译的时候产生调试相关的信息(用gdb调试程序必须加上这个选项)

例子:main.c

  1 #include<stdio.h>
  2 
  3 int main(){
  4     int n=10;
  5     for(int i=0;i<n;i++){
  6         printf("I love you!\n");
  7     }                                                                                     
  8     printf("At end\n");
  9     return 0;
 10 }         

gdb运行效果

liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gcc main.c -o main -g
liuwendong@liuwendong-virtual-machine:~/2023_5_27$ gdb main
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...done.
(gdb) break 6
Breakpoint 1 at 0x652: file main.c, line 6.
(gdb) run
Starting program: /home/liuwendong/2023_5_27/main 

Breakpoint 1, main () at main.c:6
6	        printf("I love you!\n");
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000555555554652 in main at main.c:6
	breakpoint already hit 1 time
(gdb) delete 1
(gdb) info break
No breakpoints or watchpoints.

5. 什么是gdb

gdb是GNU调试器(GNU Debugger)的简称,它是一款功能强大的调试工具,用于调试C、C++、汇编等程序。

测试文件

test.c 如下:

  1 #include<stdio.h>
  2 
  3 void myPrint(int n){
  4     for(int i=0;i<n;i++){
  5          printf("I love you!\n");
  6     } 
  7 }
  8 
  9 int main(){
 10     int a;
 11     int b;
 12     int c;
 13     int d;
 14     a=2;
 15     b=3;
 16     c=4;
 17     d=5;
 18 
 19     printf("a*b*c*d = %d\n",a*b*c*d);
 20 
 21     int n=6;
 22 
 23     myPrint(n);
 24                                                                                           
 25     return 0;
 26 }   


如何启动gdb调试:

$ gdb test 
$ gdb --args test arg1 arg2 #启动调试并设置命令行参数arg1,arg2

先进入调试界面,然后再设置命令行参数:

$ gdb test
(gdb) set test arg1 arg2 

list

(gdb) list                 #下翻源代码
(gdb) list -               #上翻源代码
(gdb) list 19              #查看19行附近的源代码
(gdb) list main            #查看main函数附近的源代码
(gdb) list test.c:5        #查看test.c文件第5行附近的源代码
(gdb) list test.c:myPrint  #查看test.c文件myPrint函数附近的源代码

操作示例:

(gdb) list
1	#include<stdio.h>
2	
3	void myPrint(int n){
4	    for(int i=0;i<n;i++){
5	         printf("I love you!\n");
6	    } 
7	}
8	
9	int main(){
10	    int a;
(gdb) list
11	    int b;
12	    int c;
13	    int d;
14	    a=2;
15	    b=3;
16	    c=4;
17	    d=5;
18	
19	    printf("a*b*c*d = %d\n",a*b*c*d);
20	
(gdb) list -
1	#include<stdio.h>
2	
3	void myPrint(int n){
4	    for(int i=0;i<n;i++){
5	         printf("I love you!\n");
6	    } 
7	}
8	
9	int main(){
10	    int a;
(gdb) list 19
14	    a=2;
15	    b=3;
16	    c=4;
17	    d=5;
18	
19	    printf("a*b*c*d = %d\n",a*b*c*d);
20	
21	    int n=6;
22	
23	    myPrint(n);
(gdb) list main
4	    for(int i=0;i<n;i++){
5	         printf("I love you!\n");
6	    } 
7	}
8	
9	int main(){
10	    int a;
11	    int b;
12	    int c;
13	    int d;
(gdb) list test.c:5
1	#include<stdio.h>
2	
3	void myPrint(int n){
4	    for(int i=0;i<n;i++){
5	         printf("I love you!\n");
6	    } 
7	}
8	
9	int main(){
10	    int a;
(gdb) list test.c:myPrint
1	#include<stdio.h>
2	
3	void myPrint(int n){
4	    for(int i=0;i<n;i++){
5	         printf("I love you!\n");
6	    } 
7	}
8	
9	int main(){
10	    int a;

break

设置断点

break/b [文件名:][行号|函数名]

info break

查看断点信息

info break
i b

delete [n]

删除n号断点

delete/d [n] -- 删除所有断点或n号断点

操作示例:

(gdb) break 19
Breakpoint 1 at 0x6dd: file test.c, line 19.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000006dd in main at test.c:19
(gdb) b 23
Breakpoint 2 at 0x706: file test.c, line 23.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000006dd in main at test.c:19
2       breakpoint     keep y   0x0000000000000706 in main at test.c:23
(gdb) delete 2
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000006dd in main at test.c:19
(gdb) d 1
(gdb) i b
No breakpoints or watchpoints.

run

启动测试

run/r

continue

继续,可以运行到逻辑上的下一个断点处

continue/c

ignore

忽略某个断点多少次

ignore N COUNT
(gdb) ignore 1 10 # 忽略1号断点3次

step

单步调试,即遇到函数调用会进入函数

step/s
(gdb) step

finish

跳出函数,即执行完整个函数

(gdb) finish

next

逐过程,即遇到函数调用,它不会进入函数,而是把函数调用看作一条语句。

next/n
(gdb) n

print

监视,可以打印表达式的值

print/p EXP
(gdb) print a*b*c

display

自动展示表达式的值

 display EXP # 自动展示EXP
 info display # 显示所有自动展示的表达式信息
 undisplay [n] # 删除所有或[n]号自动展示的表达式

操作示例:

(gdb) list 19
14	    a=2;
15	    b=3;
16	    c=4;
17	    d=5;
18	
19	    printf("a*b*c*d = %d\n",a*b*c*d);
20	
21	    int n=6;
22	
23	    myPrint(n);
(gdb) b 19
Breakpoint 1 at 0x6dd: file test.c, line 19.
(gdb) r
Starting program: /home/liuwendong/2023_5_27/test 

Breakpoint 1, main () at test.c:19
19	    printf("a*b*c*d = %d\n",a*b*c*d);
(gdb) n
a*b*c*d = 120
21	    int n=6;
(gdb) s
23	    myPrint(n);
(gdb) s
myPrint (n=6) at test.c:4
4	    for(int i=0;i<n;i++){
(gdb) finish
Run till exit from #0  myPrint (n=6) at test.c:4
I love you!
I love you!
I love you!
I love you!
I love you!
I love you!
main () at test.c:25
25	    return 0;

操作示例:

(gdb) list 18
13	    int d;
14	    a=2;
15	    b=3;
16	    c=4;
17	    d=5;
18	
19	    printf("a*b*c*d = %d\n",a*b*c*d);
20	
21	    int n=6;
22	
(gdb) b 18
Breakpoint 1 at 0x6dd: file test.c, line 18.
(gdb) r
Starting program: /home/liuwendong/2023_5_27/test 

Breakpoint 1, main () at test.c:19
19	    printf("a*b*c*d = %d\n",a*b*c*d);
(gdb) display a
1: a = 2
(gdb) n
a*b*c*d = 120
21	    int n=6;
1: a = 2
(gdb) n
23	    myPrint(n);
1: a = 2
(gdb) d 1
(gdb) break 23
Breakpoint 2 at 0x555555554706: file test.c, line 23.
(gdb) print n
$1 = 6
(gdb) ignore 2 3
Will ignore next 3 crossings of breakpoint 2.
(gdb) n
I love you!
I love you!
I love you!
I love you!
I love you!
I love you!
25	    return 0;
1: a = 2
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值