声明:这里实际用的是g++不过2者一样参数差不多,亲测可用。
编译过程
源代码–>预处理–>编译–>汇编–>链接–>可执行文件
源代码不用多说,保证没有错就行。
预处理
#include<iostream>
using namespace std;
int main()
{
int a[100];
int n = 0;
int max;
int num=0;
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> a[i];
}
cin >> max;
max += 30;
for (int i = 0; i < n; ++i)
{
if (a[i] <= max)
num++;
}
cout << num;
return 0;
}
这是自己写的源码,有点粗糙,文件名叫main1.c
g++ main1.c -o main1.i -E
-o为output,-E表示只进行预处理 输出为main1.i文件(.i文件为预处理后的文件)
# 2 "main1.c"
using namespace std;
int main()
{
int a[100];
int n = 0;
int max;
int num=0;
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> a[i];
}
cin >> max;
max += 30;
for (int i = 0; i < n; ++i)
{
if (a[i] <= max)
num++;
}
cout << num;
return 0;
}
前面省去了一大堆不懂得东西,其实这一步骤就是做一些替换。把头文件替换掉,声明之类的替换掉。
编译
g++ main1.i -o main1.s -S
输出文件为
.file "main1.c"
.section .rodata
.type _ZStL19piecewise_construct, @object
.size _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
.zero 1
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.text
.globl main
.type main, @function
main:
.LFB1455:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %ebx
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x78,0x6
.cfi_escape 0x10,0x3,0x2,0x75,0x7c
subl $432, %esp
call __x86.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
movl $0, -424(%ebp)
movl $0, -12(%ebp)
subl $8, %esp
leal -424(%ebp), %eax
pushl %eax
movl _ZSt3cin@GOT(%ebx), %eax
pushl %eax
call _ZNSirsERi@PLT
addl $16, %esp
movl $0, -16(%ebp)
.L3:
movl -424(%ebp), %eax
这一步其实就是把原本的语言替换为汇编语言。
汇编
g++ main1.s -o main1.o -c
用-c参数输出为.o文件
很显然到这一步已经变成二进制文件了不过这一步的二进制文件不能执行
root@kali:~/桌面# g++ main1.o -o main1
root@kali:~/桌面# ./main1
就能执行了
函数库
linux存在好多苦存放在/usr/lib目录下。不过想要你的库能被查找到还要按照格式命名。
库名字以lib开头,随后指明是什么库,最后加.a或.so (.a表示静态库,.so表示共享库)
libm.so表示数学的共享库。
gcc -o hello hello.c /usr/lib/libm.a
除搜索标准c语言函数库外还搜索数学库已解决引用问题跟下面命令作用相同
gcc -o hello hello.c -lm
/usr/lib/libm.a可以简写为-lm
另外,-L可以增加搜索路径
gcc -o hello hello.c -L/usr/openwin/lib -lx11
更改了搜索目录,从原本的/usr/lib改成了/usr/openwin/lib
建立小型函数库
首先建立.c文件 分别为pro1.c pro2.c分别包含一个函数
root@kali:~/桌面# cat pro1.c
#include<stdio.h>
void pro1(int arg)
{
printf("hello:%d\n",arg);
}
root@kali:~/桌面# cat pro2.c
#include<stdio.h>
void pro2(char *arg)
{
printf("OK:%s\n",arg);
}
步骤2:
把.c文件编译到汇编阶段生成.o文件。
root@kali:~/桌面# gcc pro1.c -o pro1.o -c
root@kali:~/桌面# gcc pro2.c -o pro2.o -c
步骤3:
为库文件创建一个头文件lib.h文件,声明库文件中的函数,它应该被希望使用库文件的应用程序包含
root@kali:~/桌面# cat lib.h
void pro1(int);
void pro2(char *);
步骤4:创建并使用一个库文件。用ar命令将单独文件归并到一个大的文件中。
root@kali:~/桌面# ar crv libfoo.a pro1.c pro2.c
a - pro1.c
a - pro2.c
输出为libfoo.a文件,一个静态库就完成了(还记得这个名字的含义吗,之前说过)
步骤5:
主程序
root@kali:~/桌面# cat main.c
#include"lib.h"
int main()
{
pro2("Linux world");
exit(0);
}
步骤6:编译这个程序
root@kali:~/桌面# gcc -o proc main.c -L. -lfoo
proc是输出文件,还记得-L吗是更改默认查找库的目录改为’.’也就是你的工作目录,我这里是桌面 -lfoo就是libfoo.a文件了。
root@kali:~/桌面# ./proc
OK:Linux world
有时候我们不知道某个函数在什么库中可以用下面这条很实用的命令
查找sin函数所在的库
root@kali:~/桌面# nm -o /lib/*.so|grep sin
nm: /lib/klibc-rBb4n9zs2Ri-TucnLVZwCHjM8M4.so:无符号
用make命令来编译工程
写make文件
proc: main.o pro1.o pro2.o
gcc main.o pro1.o pro2.o -o proc
main.o: main.c pro.h
gcc main.c -c
pro1.o: pro1.c
gcc pro1.c -c
pro2.o: pro2.c
gcc pro2.c -c
依赖关系图如下
用make命令生成文件
root@kali:~/桌面# make -f makefile
gcc main.c -c
main.c: In function ‘main’:
main.c:5:2: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
exit(0);
^~~~
main.c:5:2: warning: incompatible implicit declaration of built-in function ‘exit’
main.c:5:2: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
gcc pro1.c -c
gcc pro2.c -c
gcc main.o pro1.o pro2.o -o proc
除了生成了可执行文件还生成了.o的2个临时文件
简单调试
想要调试,编译时要加入调试信息
gcc -g main.c -o proc
l列出前10行
b 3 下断点于第三行
info b 查看断点信息
run 运行程序
n 步过
s 步入
c 继续运行