C语言生成dll与lib文件

环境要求

新建一个空白项目,可以是exe的,也可以直接是dll的,也可以是啥都没有的空项目,推荐创建空项目,项目创建好以后进行配置,共两步

第一步,打开项目属性
C语言生成dll与lib文件_第1张图片
第二步,设置配置类型为动态库dll,并确定
C语言生成dll与lib文件_第2张图片

编写dll库函数

test1.c

_declspec(dllexport) int test(int a, int b)
{
	return a + b + b;
}

test1.h

#pragma once
_declspec(dllexport) int test(int a, int b);

test2.c

_declspec(dllexport) int minus(int a, int b)
{
	return a - b;
}

test2.h

#pragma once
_declspec(dllexport) int minus(int a, int b);

常见问题和错误说明

声明,下述结论以测试工程为例: 
	1. 编写dll库不需要main函数,直接写函数即可,参考工程见下图1;
	2. 生成的dll文件保存路径如下:H:\Test\x64\Debug;
	3. 生成成功的标志(图2),只要输出窗口中显示1成功即可,不用理会白色的报错;
	4. 如果输出窗口中没有字(图3),那么前往 H:\Test\x64\Debug;把里面所有文件删了再重新编译运行即OK;
	5. 如果上述都不行,那么点击  生成 --> 重新生成解决方案;
	6. 编写函数时,一定要加上 _declspec(dllexport) ,不然dll文件可以正常生成,但是Python读取不了;
	7. 只写.c文件,不写.h文件,生成的dll文件python一样可以调用,不建议这么干;
	8. lib和dll文件详细说明后附;
	9. 加上 _declspec(dllexport) ,会生成 lib 文件和 dll 文件,不加只会生成dll文件;
	10. 如果工程下存在多个.c和.h文件,里面都存放了函数,随便点哪里编译运行即可,生成的dll文件会包含所有.c的函数;
	11. 无法看到dll文件中有哪些函数,想看的话可以通过小工具 dll  export viewer;
	12. 有时候头文件中会通过 extern "C" _declspec(dllexport) int minus(int a, int b); 来创建函数,
		是因为如果按照C的方式来创建,在dll经过编译器后函数名不会变,否则会被编译器修饰,例如C++调用dll时。

C语言生成dll与lib文件_第3张图片
C语言生成dll与lib文件_第4张图片
C语言生成dll与lib文件_第5张图片

Python调用dll文件

Python调用dll时,只需要dll文件
import ctypes

a = ctypes.CDLL('Test.dll')
ret = a.test(1,2)
ret1 = a.miuns(1,2)

print(ret, ret1)

C语言调用dll文件

  1. 静态调用

     1. 静态调用需要lib文件和dll文件,在程序一开始执行时就加载这个文件。
     2. 在调用前,先把lib和dll拷贝到当前工程文件夹,不然提示找不到dll,见下图。
     3. 在下面示例中,我没有声明 test 函数,但是它依然可以正常调用,是因为C会假设它存在,并执行相应操作,
     	但是这种方式不可以取,在调用时,还是显式声明一下。
    

C语言生成dll与lib文件_第6张图片

#include 
#include 
#include 

#pragma  comment(lib, "H://Test//x64//Debug//Test.lib")		// 通过关键字导入静态文件路径	
_declspec(dllimport) int minus(int a, int b);				// 声明导入函数,注意这里是import
int main() {
	int a = minus(5, 6);
	int b = test(5, 6);
	printf("%d", a);
	printf("%d", b);
}
  1. 动态调用

     1. 动态调用是比较常用的一种方法。
     2. dll文件可以通过直接指定路径的方式来添加。
     3. 动态调用是什么时候用dll,什么时候再加载dll。
     4. 流程: 实例一个句柄 --> 创建指向函数地址的指针 --> 获取函数入口地址 --> 使用函数
    
#include 
#include 
#include 

int main()
{
	HINSTANCE h = LoadLibrary(L"H://Test//x64//Debug//Test.dll");	// 实例化句柄 
	typedef int (*p_func)(int a, int b);							// 创建一个指向函数地址的指针
	p_func testfunc = (p_func)GetProcAddress(h, "test");			// 获取函数入口地址
	int a = testfunc(5, 6);
	printf("%d", a);
	return 0;
}

dll和lib的详细介绍

lib 分为两种

  1. 第一种包含了函数所在的dll文件和文件中函数入口,具体的代码由运行时dll来提供。
  2. 第二种时lib包含了代码本身,在编译时直接把代码加入到程序中。

区别

  1. lib是编译时才用,dll是运行时才用。
  2. 完成源代码编译只需lib,程序要跑起来需要用到dll。
  3. 如果存在dll文件,那么lib中一般是一些索引信息,记录函数的入口和位置,dll中是具体内容。
  4. 如果只有lib,那么这个lib是静态编译出来的,索引和代码都在里面。
  5. 如果使用静态编译的lib,那么编译时程序会全部加载到项目中,会使应用程序超级大,并且失去了动态库的灵活性,发布新版本需要发布新的应用程序。
  6. 如果不想使用lib文件,可以同win32 API提供的Loadbriary,GetProcAddress来直接调用dll。

注意事项

  1. 头文件中包含lib中说明输出的符号和数据结构,应用程序调用lib时,需要将头文件包含进去。
  2. 包含了dll中说明输出的符号和数据结构的.h文件,应用程序调用dll时,应该将.h文件引入应用程序的源文件中。
    开发成功后的应用程序在发布时,只需要.exe和.dll文件,并不需要.lib和.h文件。

你可能感兴趣的:(C,c语言,开发语言)