C语言程序编译的步骤通常包括:预处理、编译、汇编、链接。
预处理:
(1)删除#define删,展开宏定义
(2)处理条件编译指令,如#ifdef #ifndef #endif等,条件中符合判断条件的保留
(3)#include加载的文件插入到该行
(4)删除所有注释,添加行号和文件标示,方便调试
(5)保留#pragma编译器指令
gcc -E test.c -o test.i
编译:检查错误,生成汇编文件即高级语言编译生成机器可识别的汇编语言
gcc -S test.i -o test.s
汇编:将汇编文件生成二进制文件
gcc - c test.s -o test.o
链接:二进制文件与其他文件链接(如静态链接库、动态链接库)
链接生成可执行文件
gcc test.o -o test
C语言静态库
(1)编译过程中把静态库中的相关代码加载可执行文件中,运行时不需要链接库,运行速度快
(2)可执行文件占用磁盘和内存空间较大,静态库升级后,程序需要重新编译
C语言动态库
(1)编译过程中仅记录使用的动态库,不复制共享库中的相关代码,运行时加载
(2)程序运行时需加载库,动态库升级后,程序无需需要重新编译,库升级不方便
(3)占用较小的磁盘和内存空间,使用更广泛
demo:
1.编写功能(模块)文件
2.编写.h头文件
3.编写主程序
4.依据静态编译过程,编写shell脚本
5.依据动态编译过程,编写shell脚本
func.c
#include <stdio.h>
#include <stdlib.h>
void sum(int *a,int *b)
{
int sum = *a + *b;
printf("sum of two num : %d\n",sum);
}
void subtr(int *a,int *b)
{
int subtr;
subtr = abs(*a - *b);
printf("subtraction of two num : %d\n",subtr);
}
func.h
void sum(int *a,int *b);
void subtr(int *a,int *b);
pro_main.c
#include "func.h"
#include <stdio.h>
void input_num(int *pp1,int *pp2)
{
printf("input num a :\n");
scanf("%d",pp1);
printf("input num b :\n");
scanf("%d",pp2);
}
int main()
{
int *p1;
int a;
p1 = &a;
int *p2;
int b;
p2 = &b;
input_num(p1,p2);
sum(p1,p2);
subtr(p1,p2);
return 0;
}
static.sh
#!/bin/bash
source ~/.bashrc
#${1}为功能程序
#${2}为主程序
func=${1}
pro_main=${2}
func1=`basename ${1} .c`
pro_main1=`basename ${2} .c`
#编译源文件
gcc ${1} -c
#创建静态库
ar crs lib${func1}.a ${func1}.o
#ar :库文件维护程序的名称
#c:创建一个库,不管是否存在,都将创建
#r:在库中插入模块
#s:创建目标文件索引,这个在创建较大的库的时候能加快时间
#编译主程序加载静态库
gcc ${pro_main} -o ${pro_main1} -L ./ -l${func1}
#执行执行程序
./${pro_main1}
float.sh
#!/bin/bash
#添加动态库环境变量
source ~/.bashrc
#${1}为功能程序
#${2}为主程序
func=${1}
main=${2}
func1=`basename ${func} .c`
main1=`basename ${main} .c`
#编译源文件
gcc -c ${func}
#创建动态库
gcc -shared -fPIC -o lib${func1}.so ${func}
#shared:表示指定生成动态链接库,不可省略
#fPIC:表示编译为位置独立的代码,不可省略
#编译主程序加载动态库
gcc ${main} -L ./ -l${func1} -o ${main1}
#执行执行程序
./${main1}
静态库结果示例:
动态库结果示例: