0
点赞
收藏
分享

微信扫一扫

C语言-库文件与头文件


本文是对目标文件和链接文件两个概念的进化

创建一个文件print.o,里面有一个函数printff用来打印
创建一个文件main.c,调用printff函数

1:创建print.c文件,并添加如下代码

下面这段内联汇编使用intel语法,所以编译的时候需要指定语法为intel语法,而不是AT&T

void printff(char * arr,int lenth){

__asm__(
"mov rax,1;"
"mov rdi,1;"
"syscall;"
:
:"S"(arr),"d"(lenth)
);
}

2:使用下面的命令,生成目标文件:print.o

// 指定内联汇编语法为intel语法
gcc -c print.c -masm=intel

3:使用下面的命令,通过目标文件生成库文件:lib_print

// ar是GCC工具集里的一个工具
// r选项表示如果库中有同名函数,则覆盖
// lib_print是库的名字,名字随便起,不过一般都以lib开头
ar r lib_print print.o

至此,库文件lib_print已经生成,里面有一个printff函数
4:接下来创建一个main.c,并在这个文件中使用printff函数

void printff(char *,int len);

int main(){
char arr[] ="hello world!lib\n";
printff(arr,16);
}

5:使用下面的命令,编译main.c,此时会生成a.out文件

// 编译main.c的时候,用到了库lib_print中的函数,所以需要加上lib_print
gcc main.c lib_print

6:运行a.out文件

// 打印出hello world!lib
./a.out

库文件实在是太麻烦了,因为我的库发行出去给别人用的时候,别人怎么知道我的库中有哪些函数?库又不不是可读的,一打开就乱码,所以使用头文件的方式来解决这种复杂的问题,就是当发行库的时候,同时顺便发行该库的头文件

7:下面我新建了一个叫print.h的文件,并写了如下代码
只能手写,GCC没有工具提供自动生成.h文件

void printff(char * arr,int lenth);

8:然后将main.c中原来的代码修改成如下代码

// 由原来的void printff(char *,int len);
// 改成了#include "print.h"
#include "print.h"
int main(){
char arr[] ="hello print.h\n";
printff(arr,14);
}

9:使用下面的命令重新编译并生成a.out文件(与步骤5相同)

gcc main.c lib_print

7:运行a.out文件

// 打印出hello world!lib
./a.out

创建动态链接库(DLL)及隐式链接该DLL==========下面重新整理
首先,在Visual Studio下新建一个Dll项目
选择文件->新建项目->Visual C+±>Windows桌面->动态链接库(DLL),我给这个项目起个名,叫DLL1,点击确定按钮即可

在项目中的Dll1.cpp文件中写如下代码

#include "stdafx.h"
#include <iostream>

_declspec(dllexport) void aa() {
std::cout << "dll method aa";
}

方法aa简单的打印出了一句话,会发现在方法前面有_declspec(dllexport),这个的意思表示方法aa要在别的程序中使用,也就是说,别的程序中要想使用这个aa方法,那么必须将aa方法公布出去才行,这个_declspec(dllexport)就是做公布用的

至此,DLL文件已经创建完成,我们点击菜单按钮[生成->生成解决方案]或者[生成->生成Dll1]都可以,点击之后我们会发现控制台出现下面这段信息

1>dllmain.cpp
1>正在生成代码...
1> 正在创建库 C:\Users\史文天\source\repos\Dll1\Debug\Dll1.lib
和对象 C:\Users\史文天\source\repos\Dll1\Debug\Dll1.exp
1>Dll1.vcxproj -> C:\Users\史文天\source\repos\Dll1\Debug\Dll1.dll
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 ==========

不难发现,其中一个文件.dll,还有一个文件是.lib,这个.lib叫做引入库文件,使用dll的方式用两种,一种是隐式链接方式使用dll,一种是显式链接使用,当使用隐式链接方式的时候,则用到.lib文件(显式链接不使用.lib文件),假设程序A通过隐式方式使用了该dll,那么.lib文件的作用则是:告知程序A,该dll里的函数是从内存中具体哪个地址开始的,就是说程序A只有通过.lib文件才能知道这个dll里面函数的地址

我们再新建一个Windows控制台项目,名字叫UseDLL1,这个项目用来使用刚才我创建的Dll1

首先,在Visual Studio中对UseDLL1项目引用.lib文件,假设我把刚才生成的lib文件放到了D盘ys文件夹,它的路径是:D:\ys\dll1.lib那么要做两步
1.告知Visual Studio这个lib文件(导入库文件)在哪个文件夹下
2.告知Visual Studio这个lib文件在这个文件夹下叫什么

设置1:项目->属性->配置属性->链接器->常规->附加库目录->输入"D:\ys"
设置2:项目->属性->配置属性->链接器->输入->附加依赖项->追加"dll1.lib"

至此,引入库文件(lib文件)已经成功导入UseDLL1项目中,这个时候,如果UseDLL1项目链接Dll1.dll,那么就可是使用Dll1.dll中的aa方法了,注意,这里有个有意思的问题,就是UseDLL1如何知道Dll1.dll在哪呢???其实通过上文,我们自己从控制台得知,这个dll在我的电脑上的C:\Users\史文天\source\repos\Dll1\Debug\Dll1.dll这个位置,但是,我的这个新项目UseDLL1是不知道的,先不急,先在UseDLL1中写代码,UseDLL1.cpp代码如下

#include "pch.h"
#include <iostream>

void aa();

int main()
{
aa();
return 0;
}

运行这段代码,很不幸,系统提示"由于找不到Dll1.cll,无法继续执行代码"

那么我应该把我刚才生成的dll放到哪里??才能让我现在的项目找到它呢??在windows下,按照约定,必须把dll文件放到下面五个地址中之一,才可以正确使用dll,他们分别是
1.应用程序EXE文件所在的同一目录(就是和.sln文件同一个文件夹下的Debug文件夹下)
2.进程当前的工作目录,可以通过API函数GetCurrentDirectory获取
3.windows系统目录c:\windows\system32
4.windows目录c:\windows,可以通过函数GetWindowsDirectory获取
5.在Path环境变量下的所有目录

现在我随便选一个,就选第4个吧,就把我刚才生成的dll放到c:\windows文件夹下,再次运行程序,非常成功的输出了(此规则实际就是各种命令也要遵循的规则,例如java命令)

dll method aa

总结:
1.创建dll,会生成两个文件,一个.dll,一个.lib
2.当隐式链接使用dll时,需要.lib
3.当显式使用dll时,不需要.lib,而是通过硬编码方式调用api获取dll
4.其他程序若想使用dll,则必须去上述五个位置去寻找dll,找不到就报错
5.找到了dll,若想调用dll里面的方法,则必须知道dll里面方法在内存中的起始地址,这个起始地址需要根据.lib文件获取,所以必须在vs中配置.lib文件(配置lib文件有三种方式
(1)工程属性中设置
(2)使用命令#pragma comment
(3)本文所用的,也是最方便的,在vs中配置)


举报

相关推荐

0 条评论