• 关于C和C++动态链接库的几个问题


    问题:

         1.写一段C++程序,编译成动态链接库后,C程序怎么访问?

         2.写一段C程序,编译成动态链接库后,C++程序怎么访问?

         3.写一个类,编译成动态链接库后,里面的public变量能否访问? 

         对于以上问题,我在Visual C++ 6.0上进行了实验。以下是实验的过程和初步结论。 

         1. 建立动态链接库是在新建工程中选择Win32 Dynamic-Link Library,建立空的工程,在里面添加头文件和实现文件(C程序用.c后缀,C++程序用.cpp后缀),以下给出C程序写的动态链接库代码和C++写的动态链接库代码(只包含一个Add函数):

    Case 1:C程序的动态链接库代码: 

    //CLib.h
    
    #ifndef C_LIB_H
    
    #define C_LIB_H
    
    extern int __declspec(dllexport) add(int x,int y);
    
    #endif
    
     
    
    //CLib.c
    
    #include "Clib.h"
    
    int add( int x, int y )
    
    {
    
    return x + y;
    
    }

     Case 2:C++程序的动态链接库代码:

    //CplusplusLib.h
    
    #ifndef LIB_H
    
    #define LIB_H
    
    extern "C" int __declspec(dllexport) add(int x, int y);
    
    #endif
    
     
    
    //CplusplusLib.cpp
    
    #include "CplusplusLib.h"
    
    int add( int x, int y )
    
    {
    
    return x + y;
    
    }

          由此可发现,其代码唯一不同的地方在于extern int __declspec(dllexport) add(int x,int y) 这一导出语句,在C程序中没有”C” ,而在C++程序多了一个标识”C”。

          发生这个区别的原因是由于C++编译器与C编译器在对程序进行编译的时候,对函数声明的编译会有区别,加上”C”,是为了告诉C++编译器,使用C编译器的方式对这一个函数声明进行编译。这样,在C程序调用C++写的动态链接库的时候,才不会发生因为寻找不到对应的函数名(编译后的)而发生Link错误。 

          再来看调用,调用方式有两种:静态和动态。这的确是印证了老师说的万事皆有两面的道理。

          使用动态的方式调用,不管在C还是在C++中,代码都是一样的,下面给出一个例子: 

    typedef int(*lpAddFun)(int, int);
    
     
    
    int main(int argc, char* argv[])
    
    {
    
           HINSTANCE hDll;
    
           lpAddFun addFun;
    
           hDll = LoadLibrary("..//..//Debug//CplusplusDLL.dll");
    
           if (hDll != NULL)
    
           {
    
           addFun = (lpAddFun)GetProcAddress(hDll, "add");
    
           if (addFun != NULL)
    
           {
    
                  int result = addFun(2, 3);
    
                  printf("%d", result);
    
           }
    
           FreeLibrary(hDll);
    
           }
    
           return 0;
    
    }

          思路是定义一个函数指针,在主程序中使用LoadLibrary这个库函数载入DLL,然后再用GetProcAddress这个库函数获得DLL中函数所在的位置。调用完函数后使用FreeLibrary这个库函数释放DLL资源。 

          然而在静态的方式中,C和C++的调用就略有不同,下面给出C++调用C库的程序: 

    // CplusplusApplicationStaticInvoke.cpp : Defines the entry point for the console application.
    
    #include "stdafx.h"
    
    #pragma comment(lib,"CDLL.lib")
    
    extern "C" __declspec(dllimport) add(int x,int y);
    
    int main(int argc, char* argv[])
    
    {
    
           int result = add(2,3);
    
           printf("%d",result);
    
           return 0;
    
    }

           #pragma comment(lib,"CDLL.lib")这一句是表示在链接的时候将CDLL.dll这个动态链接库链接到这个程序当中。 

           而在C调用C++库的例子中:

    // CApplicationStaticInvoke.cpp : Defines the entry point for the console application.
    
    #include "stdafx.h"
    
    #pragma comment(lib,"CplusplusDLL.lib")
    
    extern __declspec(dllimport) add(int x,int y);
    
    int main(int argc, char* argv[])
    
    {
    
           int result = add(2,3);
    
           printf("%d",result);
    
           return 0;
    
    }

           明显看到extern __declspec(dllimport) add(int x,int y); 与上一例子不同,少了一个”C” 

          这个原因很明显,就是为了动态库中的函数名进行对应。在CDLL中函数当然是使用C编译器的方式进行编译的,所以在调用程序中,在声明外部函数的时候,必须加上”C”,以使的这个C++程序,在编译的时候使用C编译的方法对这个外部函数声明进行编译,否则在编译运行的时候就会报链接错误。在C++调用C的例子中我们将”C”去掉,结果:

    LNK2001: unresolved external symbol "__declspec(dllimport) int __cdecl add(int,int)" (__imp_?add@@YAHHH@Z)

    上面add@@YAHHH@Z就是add函数用C++的编译方法编译后的得到的函数名,而C编译得到的应该是_add,链接的时候匹配不成功,因此就报错了。

           2. 关于类的public变量能够被访问,能否被直接访问,这里我仍没有找出答案,等待老师解答,但是有一个间接的方法能访问到类里面的变量。就是使用类的全局变量,将其导出即可,例子如下: 

    #ifdef CLASSDLL_EXPORTS
    
    #define CLASSDLL_API __declspec(dllexport)
    
    #else
    
    #define CLASSDLL_API __declspec(dllimport)
    
    #endif
    
     
    
    class CLASSDLL_API CClassDLL {
    
    public:
    
           CClassDLL(void);
    
           //Added public member
    
           int testNumber;
    
           // TODO: add your methods here.
    
    };
    
     
    
    extern CLASSDLL_API int nClassDLL;
    
    CLASSDLL_API int fnClassDLL(void);

          上面的标准宏是为了对导入导出进行匹配,这里先略过。

          注意extern CLASSDLL_API int nClassDLL; 这句代码定义了这个DLL中的一个全局变量。注意这个时候宏CLASSDLL_API应该是__declspec(dllexport)表示导出该变量。 

         在调用的时候:

    #pragma comment(lib,"ClassDLL.lib")
    
    extern int _declspec(dllimport) nClassDLL;
    
    int main()
    
    {
    
    …
    
    }

           这样就可以直接在程序中访问nClassDLL了。

  • 相关阅读:
    KooTeam
    nopCommerce架构分析系列(一)nopCommerce简介
    NServiceBus最流行的开源企业服务总线 for .Net资源学习篇
    How to become a software architect?
    DotNetMQ: A Complete Message Queue System for .NET
    CSLA.Net专注电子商务 – Focus on eCommerce
    .net framework从1.0说到4.0
    ERP/SCM
    泛型接口的协变和逆变
    HTML5学习
  • 原文地址:https://www.cnblogs.com/China3S/p/3267113.html
Copyright © 2020-2023  润新知