这篇文章比较详细地介绍了gcc工具的基本使用,下面主要对一些内容进行补充。
gcc 在这里代指 gcc编译工具链,一个 .c 文件需要经过如下四个步骤生成最终的可执行文件

我们可以一步步执行命令生成可执行文件,也可以直接使用 gcc hello.c -o a.out 生成可执行文件。
下图展现了gcc常用的一些参数

-I 指定头文件目录hello.c
#include
#include "hello.h"
int main()
{
int a = NUM;
printf("Hello %d!\n",a);
return 0;
}
hello.h
#ifndef NUM
#define NUM 20
#endif
一般都将头文件放入 include 文件夹,那么编译生成可执行文件需要指定头文件目录:
gcc hello.c -Iinclude -o a.out
-D 编译时定义宏我们可以在编译时指定宏来实现代码的注释与否以进行DEBUG等行为。
hello.c
#include
#include "hello.h"
int main()
{
int a = NUM;
printf("Hello %d!\n",a);
#ifdef DEBUG
printf("DEBUG\n");
#endif
return 0;
}

-On n=0~3 进行编译优化test.c

gcc -S test.c -o test.s
test.s

gcc -S test.c -O3 -o test.s

可见编译优化后将上面复杂代码优化为 int d = 10。
正常开发一个软件需要将头文件放进 include 文件夹,源文件放入 src 文件夹,并可以将源程序编译生成的多个可执行文件放入函数库中,这样在给用户程序时就可以不需要提交源代码。
而函数库分为静态库与动态库(共享库),下面首先介绍静态库。

目录结构如下:

main.c
#include
#include "main.h"
int main()
{
int a = 10;
int b = 5;
printf("%d %d\n", add(a,b), sub(a,b));
return 0;
}
main.h
#ifndef MAIN_H
#define MAIN_H
int add(int x, int y);
int sub(int x, int y);
#endif
acc.c
#include "main.h"
int add(int x, int y)
{
return x + y;
}
sub.c
#include "main.h"
int sub(int x, int y)
{
return x - y;
}
gcc *.c -c -I./include 生成对应.o文件
ar rcs libmytest.a *.o 生成静态库libmytest.a
gcc main.c -L./lib -lmytest -Iinclude -o app 生成可执行文件app。
除了静态库,还有动态库,其各有各自的优点和缺点。

目录结构如下:

gcc -fPIC *.c -c -Iinclude 生成与位置无关的目标文件,这是因为动态库的目标文件是运行时动态加载进目标程序中,所以需要目标文件与位置无关,即相对位置。gcc -shared -o libmytest.so *.o 制作动态库gcc main.c -L./lib -lmytest -I./include -o app 使用动态库.app 执行生成的可执行文件ldd app 发现 libmytest 找不到
ld-linux.so.2)指定好动态库libmytest.so的路径。这里有四个解决方案,第一个方案是临时方案,二至四个方法都是永久设置,其中永久设置最好使用第四种方法。
export LD_LIBRARY_PATH=库路径,将当前目录加入环境变量,但是终端退出了就无效了。.bashrc文件中/usr/lib/【/lib】目录下。(受libc库的启发)libmytest.so 所在目录的绝对路径追加入到 /etc/ld.so.conf 文件,sudo ldconfig -v 更新
getmin.h
#ifndef GETMIN_H
#define GETMIN_H
int getmin(int a[], int l, int r);
#endif
getmin.c
#include "getmin.h"
int getmin(int a[], int l, int r)
{
int i;
int mi = a[l];
int pos = l;
for(i=l+1; i<r; ++i)
{
if(a[i] < mi)
{
mi = a[i];
pos = i;
}
}
return pos;
}
sort.h
#ifndef SORT_H
#define SORT_H
void sort(int a[], int n);
#endif
sort.c
#include "getmin.h"
void sort(int a[], int n)
{
int i;
for(i=0; i<n; ++i)
{
int pos = getmin(a, i, n);
int temp = a[pos];
a[pos] = a[i];
a[i] = temp;
}
return ;
}
main.c
#include
#include "sort.h"
int main()
{
int a[10] = {5, 1, 3, 2, 4, 6, 9, 0, 8, 7};
for(int i=0; i<10; ++i)
printf("%d ", a[i]);
printf("\n");
sort(a, 10);
for(int i=0; i<10; ++i)
printf("%d ", a[i]);
printf("\n");
}
我们可以使用 gcc *.c -g -o app 生成可调试的程序。
然后使用 gdb app 可以开始调试

l 列出代码(包含main函数的程序)的10行

l 文件名:行数 显示文件名行数开始的十行代码

l 文件名:函数名 显示文件名里的函数

Enter回车 可以执行前一条命令

start 单步执行,运行程序,n 执行下一行

b 行号 设置断点,r 运行程序在断点处停止,断点可以加判断比如 b 行号 if i==5

p 变量名 可以打印变量,display 变量名 可以追踪变量

s 执行下一行,且可进入函数体内部,finish 可以结束当前函数,返回到函数调用点,这时需要断点代码执行完毕或者删除断点,删除断点可以先使用 info b 查看断点编号,然后d 断点编号删除该断点

set var i=5 可以设置变量 i 为5

undisplay 编号 可以取消追踪变量,可以使用 info display 查找变量编号。
``