多目标文件的链接
为了使程序的模块化更强,代码更易于分类管理,有时需要将同类型的代码存储在一个文件中。这时每一个文件代表着一类函数代码。这些代码使用同样的资源,完成同样的操作。由于代码被划分为若干模块。这时就会导致多个C语言文件(模块)链接的问题
代码示例:
//test.c
#include <stdio.h>
#include "my_methods.h"
int main(int argc, char const *argv[])
{
printf("和为:%d",add(4,3));
my_printf();
return 0;
}
//my_methods.h
int add(int a,int b);
void my_printf();
//my_methods.c
#include <stdio.h>
#include "my_methods.h"
int add(int a,int b){
return a+b;
}
void my_printf(){
printf("hello my abilety is say hello");
}
- 在命令行窗口中编译该程序如下。
gcc test.c my_methods.c -o main
- 在命令行窗口中运行该程序如下。
./main
image.png
成功运行。。。
接着我有些了一个程序是如下
//test.c
#include <stdio.h>
// extern int add(int a,int b);
// extern int sub(int a,int b);
// extern int mul(int a,int b);
// extern int div(int a,int b);
// extern void my_printf(void);
int main(int argc, char const *argv[])
{
printf("%d\n",add(4,2));
printf("%d\n",sub(4,2));
printf("%d\n",mul(4,2));
printf("%d\n",div(4,2));
my_printf();
return 0;
}
//opera.c
#include <stdio.h>
char str[] = "i am a string!";
int add (int a,int b){
return a+b;
}
int sub(int a,int b){
return a-b;
}
int mul(int a,int b){
return a*b;
}
int div(int a,int b){
return a/b;
}
void my_printf(){
printf("%s\n",str);
}
紧接着编译,发现编译有警告,但是能正常运行
image.png
这是因为编译器在处理 add等 函数调用时没有找到 add 函数的原型,只能根据 add(4, 2) 函数调用“推测”,若是把test.c中的注释去掉就不会有问题了。
extern
extern 的字面意思是“外部的”,它也是 C 语言中的一个关键字,表示“外部符号”。你已经知道 C 语言编译器需要知道函数的原型,所以在 main.c 中,正确的做法应该是:
#include <stdio.h>
extern int add(int a, int b);
// 或 int add(int a, int b);
int main()
{
char i = 7;
printf("3+4=%d\n", add(3, 4));
printf("3+7=%d\n", add(3, i));
return 0;
}
这样编译器就知道 add 函数的原型了,也知道它来自于外部文件。实际上,函数声明中的 extern 也可以不写,不过不写 extern 仍然表示 add 函数是外部符号。
当然extern也可以修饰变量,就像这样extern int a ;
引入外部变量时,extern 不能省略。extern int a;
不是定义变量,因此不会为 cnt 分配空间。当然如果你在外部是已经给这个变量初始化赋值的话,你在引入外部变量在赋值,就会编译报错,是非法的
如果不希望外界使用本文件里定义的函数,或者变量,该怎么办呢?答案是使用 static 关键字。以前我们使用过 static 来定义静态变量,它其实还表示变量或者函数属于“内部符号”,有 static 修饰的全局变量和函数在外部文件中都是不可见的。
Linux 静态库和动态库
一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。
程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态加载函数库(dynamically loaded libraries):
1、静态函数库,是在程序执行前就加入到目标程序中去了 ;
2、动态函数库同共享函数库是一个东西(在linux上叫共享对象库, 文件后缀是.so )
静态库
步骤
1.编写源代码文件,生成目标文件
gcc -c <源代码文件,如main.c>
2.归档目标文件,得到静态库
我们使用ar将目标文件归档,如下
ar crv 归档文件 目标文件列表
如ar crv libmylib.a my_math.o
我们就得到了libmylib.a,这就是我们需要的静态库。
上述命令中 crv 是 ar的命令选项:
c 如果需要生成新的库文件,不要警告
r 代替库中现有的文件或者插入新的文件
v 输出详细信息
通过 ar t libmylib.a 可以查看 libmylib.a 中包含的目标文件。
可以通过 ar --help 查看更多帮助。
注意:我们要生成的库的文件名必须形如 libxxx.a ,这样我们在链接这个库时,就可以用 -lxxx。
反过来讲,当我们告诉编译器 -lxxx时,编译器就会在指定的目录中搜索 libxxx.a 或是 libxxx.so。
3.编写对应的头文件,测试静态库
gcc test.c -L. -lmylib
将会生成a.out,通过 ./a.out 可以运行该程序。说明我们的静态库能正常工作。
上面的命令中 -L. 告诉 gcc 搜索链接库时包含当前路径, -lmylib 告诉 gcc 生成可执行程序时要链接 libmylib.a。
共享库
步骤
1.编写源文件
2.编译生成共享库
gcc -fPIC -shared -o libmax.so max.c
参考
https://www.cnblogs.com/hzh1024n/archive/2009/09/17/1568357.html
https://blog.csdn.net/u012662731/article/details/53783401
https://www.cnblogs.com/sunsky303/p/7731911.html
https://www.jianshu.com/p/74003997b48c
有待补充
网友评论