zoukankan      html  css  js  c++  java
  • VS2017生成一个简单的DLL文件 和 LIB文件——C语言

    下面我们将用两种不同的姿势来用VS2017生成dll文件(动态库文件)和lib文件(静态库文件),这里以C语言为例,用最简单的例子,来让读者了解如何生成dll文件(动态库文件)

    生成动态库文件

    姿势一:

    第一步:新建一个项目

    第二步:选择Windows桌面向导(这里先不要去管上面的“动态链接库(DLL)”)

     第三步:选择动态链接库,并空项目打勾√

     第四步:添加一个.c源文件

    第五步:(因为这里以C语言为例子,将后缀改为.c)

    第六步:在c文件中输入一个简单的函数这里使用了_declspec(dllexport),但_declspec(dllexport)并不是必须的,后面一种方法将不使用_declspec(dllexport)

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

    第七步:新建一个头文件

     第八步:在头文件中输入函数的声明

    第九步:编译

    第十步:Debug文件夹下的两个文件DLL.dll和DLL.lib就是我们要使用的两个文件了

    因为使用的_declspec(dllexport),虽然这里我们只编译了一次,却生成了dll和lib两个文件

    姿势二

    第一步到第五步和上面的步骤一模一样,这里从第六步开始讲起

    第六步:在c文件中输入一个简单的函数(注意这里就没有使用_declspec(dllexport)

    第七步:添加一个头文件

    第八步:在头文件中输入函数的声明

    第九步:编译

    第十步:这时在Debug文件里就可以看出两种方法的区别了,第二种方法没有加 _declspec(dllexport) 只有一个dll文件,如果我们也想要lib文件,需要额外几个步骤

    生成lib文件

    第十一步:点击项目——》DLL属性

    第十二步:配置属性——》项目默认值——》配置类型,把动态库(.dll) 改为 静态库(.lib)

    第十三步:编译

    第十四步:这个时候Debug文件夹里面就多出了一个lib文件

    从上面两个例子可以看出:

    在生成dll文件(动态库文件)时,如果不使用_declspec(dllexport)那么就只有dll文件,在这种情况下就无法使用#pragma comment来隐式装载动态库(因为需要lib文件),只能使用LoadLibrary来显式装载动态库(使用Loadlibrary只需要dll文件

    如果使用了_declspec(dllexport)那么就既有dll文件,也有lib文件

    还有一点需要注意的是,如果在源文件(.c文件)中函数的定义没有_declspec(dllexport),但是在头文件中函数的声明使用了_declspec(dllexport)此时编译产生的文件只有dll文件如果改成源文件中有_declspec(dllexport),头文件中没有_declspec(dllexport),那么编译产生的文件既有dll文件也有lib文件

    (导出dll文件时最好还是在源文件和头文件中都加上_declspec(dllexport)

    笔者记录了一下加与不加_declspec(dllexport)对导出dll文件大小的影响,以上面的代码为例

    (造成dll文件大小不同的原因,笔者暂时无法给出解释,待补充)

    生成静态库文件

    和生成dll文件步骤相似,这里就不再赘述了,直接上图

    第一步:

    第二步:建议把预编译标头的勾去掉,(不去掉也没事,只是本文为了简洁,让读者更清楚的生成步骤)

    第三步:

    第四步:

    第五步:

    在源文件中输入以下代码:

    int sum(int a, int b)
    {
        return a + b;
    }

    第六步:

    第七步:

    第八步:

    第九步:编译,可以看到Debug文件夹下有一个lib文件

    (注意:不要像我一样傻fufu的,在导出lib文件的时候还加上_declspec(dllexport)(之前我的确这么干过),如果加了_declspec(dllexport),在Debug文件夹里面也只有lib文件,lib文件也能正常使用,

    但是不建议加)

    还有一点就是,生成dll文件(动态库文件)时产生的lib文件,和生成lib文件(静态库文件)时产生的lib文件的作用不相同,从文件大小也能看出来(一个1.58KB一个3.92B)

    关于lib和dll文件的区别可以看一下这一盘文章:lib 和 dll 的区别、生成以及使用详解

     笔者记录了一下加与不加_declspec(dllexport)对导出lib文件大小的影响,以上面的代码为例

    (至于为什么加了_declspec(dllexport)后,lib文件会出现0.02KB的差别,笔者暂时无法给出解释,待补充)

    有的读者可能会发现在网上很多博客写关于生成dll文件时,头文件里面的写法是这样的

    刚接触预处理命令的读者看着可能会有点不好理解,下面对上面的头文件中的代码逐个分析,笔者将上面的代码分为两个个部分(对预处理命令不是很熟悉的读者可以先看一下这一篇随笔:

    预处理命令使用详解----#if、#endif、#undef、#ifdef、#else、#elif

    第一部分:

    #pragma once
    #ifdef DLL_EXPORTS
    #define DLL _declspec(dllexport)
    
    #else
    #define DLL _declspec(dllimport)
    
    #endif

    把上面的代码翻译一下就是:如果DLL_EXPORTS这个宏名已经被定义,那么DLL就等价于_declpsec(dllexport),否者DLL就等价于_declspec(dllimport),#pragma once保证了该头文件只被包括(#include)一次,

    在很多头文件中都可以看到#pragma once,比如stdio.h

    读者这个时候可能就有疑问了,明明我没有#define DLL_EXPORTS,为什么是执行#define DLL _declspec(dllexport)而不是#define DLL _declspec(dllimport)呢?

    首先读者需要知道的是DLL_EXPORTS是一个预定义的宏,因为我们是生成的是DLL文件

    可以在属性->配置属性->C/C++->预处理器中看到

    现在读者应该清楚了,在生成DLL文件时,编译器已经预定义了DLL_EXPORTS这个宏名,如果我们是生成的应用程序

    上面的代码写成

    #ifdef
    ```
    #else
    ```
    #endif

    这种形式是为了方便在使用的时候lib或者dl文件时,需要引入头文件的时候方便一点,不需要对头文件做任何的修改(因为如果我们使用的配置类型是“应用程序(.exe)”,那么就没有预定义DLL_EXPORTS)

    第二部分:

    #ifdef _cplusplus
    extern "C"
    {
    #endif
        DLL int sum(int a, int b);
    #ifdef _cplusplus
    }
    #endif

    把上面的代码翻译一下就是:如果是C++文件(.cpp后缀)那么就是

    extern "C"
    {
        DLL int sum(int a, int b);
    }

    如果不是C++文件,那么就是

    DLL int sum(int a, int b);

    关于extern "C"作用,可以看一下这篇文章:深入理解C/C++混合编程(关于#ifdef __cplusplus extern "C" {...}的用法)

    总结一下:

    生成动态库文件

    头文件:

     1 #pragma once
     2 #ifdef DLL_EXPORTS
     3 #define DLL _declspec(dllexport)
     4 
     5 #else
     6 #define DLL _declspec(dllimport)
     7 
     8 #endif
     9 
    10 #ifdef _cplusplus
    11 extern "C"
    12 {
    13 #endif
    14     DLL int sum(int a, int b);
    15 #ifdef _cplusplus
    16 }
    17 #endif

    源文件:

    1 _declspec(dllexport) int sum(int a, int b)
    2 {
    3     return a + b;
    4 }

    编译之后产生:

    生成静态库文件:

    头文件:

     1 #pragma once
     2 
     3 #ifdef _cplusplus
     4 extern "C"
     5 {
     6 #endif
     7     int sum(int a, int b);
     8 #ifdef _cplusplus
     9 }
    10 #endif

    源文件:

    1 int sum(int a, int b)
    2 {
    3     return a + b;
    4 }

    编译后产生:

    到这里本文就基本结束了,上面详细叙述了生成dll文件(动态库文件)和lib文件(静态库文件)的步骤,关于lib文件和dll文件的使用将在另一篇随笔中详细介绍

  • 相关阅读:
    boost之实用工具
    boost之内存池
    boost之智能指针
    boost之日期date_time
    boost之时间timer
    boost之网络通信
    boost之定时器和io_service
    【Linux 线程】线程同步《一》
    【Linux 线程】常用线程函数复习《四》
    【Linux 线程】常用线程函数复习《三》
  • 原文地址:https://www.cnblogs.com/lanhaicode/p/10798385.html
Copyright © 2011-2022 走看看