编译

目标代码文件、可执行文件和库

C 编程的基本策略是使用程序将源代码文件转换为可执行文件,此文件包含可以运行的机器语言代码。C 分两步完成这一工作:编译和链接。编译器将源代码转换为中间代码,链接器将此中间代码与其他代码相结合来生成可执行文件。
编译器将源代码转换成机器语言代码,将结果放置在一个目标代码文件中。虽然目标文件包含机器语言代码,但是该文件还不能运行。
目标代码文件中所缺少的第一个元素是一种叫做启动代码(start-up code)的东西,此代码相当于您的程序和操作系统之间的接口;
所缺少的第二个元素是库例程的代码。几乎所有 C 程序都利用标准 C 库中所包含的例程(称为函数)。目标代码文件不包含这一函数的代码,它包含声明使用 printf() 函数的指令。实际代码存储在另一个称为“库”的文件中。库文件中包含许多函数的目标代码。
链接器的作用是将这 3 个元素(目标代码,系统的标准启动代码,库代码)结合在一起,并将它们存放在单个文件,及可执行文件中。

Linux 编译

1
2
3
4
5
6
#include <stdio.h>
int main(void)
{
printf("Hello World!\n");
return 1;
}
1
2
gcc hello.c # 编译
a.out # 执行

调试

参数

gdb
file : 加载被调试的可执行程序文件
r: Run,运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处
c: Continue,继续执行被调试程序,直至下一个断点或程序结束
b :
b : Breakpoint,设置断点
d [编号]: Delete breakpoint,删除指定编号的某个断点。断点编号从 1 开始递增
s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数
n: 执行一行源程序代码,此行代码中的函数调用也一并执行
(s 相当于 “Step Info” 单步跟踪进入,n 相当于 “Step Over” 单步跟踪)
p : Print,显示指定变量的值
q: Quit,退出 GDB 调试环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>

int nGlobalVar = 0;

int tempFunction(int a, int b)
{
printf("tempFunction is called, a = %d, b = %d\n", a, b);
return a + b;
}

int main(void)
{
int n;

n = 1;
n++;
n--;

nGlobalVar += 100;
nGlobalVar -= 12;

printf("n = %d, nGlobalVar = %d\n", n, nGlobalVar);

n = tempFunction(1, 2);
printf("n = %d", n);
return 0;
}
1
2
3
4
5
6
7
# debug.c 源文件
# -g 编译的时候产生编译信息
# -o 指定目标文件名称
# 编译源文件
gcc -g -o debug debug.c
# debug 目标文件
gdb debug

转载于CSDN