问题:

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(, );

              printf("%d", result);

       }

       FreeLibrary(hDll);

       }

       return ;

}

思路是定义一个函数指针,在主程序中使用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(,);

       printf("%d",result);

       return ;

}

#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(,);

       printf("%d",result);

       return ;

}

明显看到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了。

关于C和C++动态链接库的几个问题的更多相关文章

  1. 【腾讯Bugly干货分享】动态链接库加载原理及HotFix方案介绍

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57bec216d81f2415515d3e9c 作者:陈昱全 引言 随着项目中动 ...

  2. MacOS平台下@rpath在动态链接库中的应用

    一.背景介绍 公司开发的一个底层库被用在了Mac平台的多个产品中.在开发这个底层库的初期,对于Mac OSX下的Install name 并没有过多的了解.对于XCode中的install name项 ...

  3. 关于 .NET Core 动态链接库的开发

    上个月月底,VS2017RC版发布了,一个很大的特点就是将原来的xProj文件又改回了csproj了. 这样一改,其实很多新的问题也暴露出来了,最严重的问题就是Net版本兼容性. 原来的Net体系大致 ...

  4. vc下的静态链接库与动态链接库(一)

    一.静态库与动态库的区别 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Lib ...

  5. 编译可供C#调用的C/C++动态链接库dll文件

    编译可供C#调用的C/C++动态链接库dll文件,C语言控制台应用程序,探索生成dll过程 由于项目需求,需要公司另一个团队提供相关算法支持,是用C语言编译好的dll库提供给我们进行调用. 但是拿到d ...

  6. C/C++ 静态链接库(.a) 与 动态链接库(.so)

    平时我们写程序都必须 include 很多头文件,因为可以避免重复造轮子,软件大厦可不是单靠一个人就能完成的.但是你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了! 库有两种, ...

  7. linux下动态链接库解决方案(二)

    以前写过一个关于linux下用c++写动态链接库无法通过的解决方案,今天看到<linux C程序设计-王者归来>这本书,书中有个更容易的解决方案,特此记录下来 书中使用的是c语言,我改用c ...

  8. Linux 动态链接库

    如何使用动态链接库 Linux下打开使用动态链接库需要三步(实际上和windows下基本一样):1.加载动态链接库,通过调用库函数dlopen()获得链接库的句柄,对应于windows下的 AfxLo ...

  9. VC++动态链接库(DLL)编程深入浅出(zz)

    VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...

  10. [转载:]C#与Fortran混合编程之本地调用Fortran动态链接库

    前言 C#发展到现在,已是一门相当完善的语言,他基于C语言风格,演化于C++.并依靠强大的.NET底层框架.C#可以用来快速构建桌面及Web应用.然而在我们的实际工作中,尽管C#已经非常完善,但还是不 ...

随机推荐

  1. Hadoop_10_shuffle02_详解Shuffle过程【来源网络】推荐更为详细

    网址:http://www.cnblogs.com/felixzh/p/4680808.html Shuffle过程,也称Copy阶段.reduce task从各个map task上远程拷贝一片数据, ...

  2. 寒假D1 B

    B - B Crawling in process... Crawling failed Time Limit:0MS     Memory Limit:0KB     64bit IO Format ...

  3. 【转】包管理器Bower详细讲解

      包管理器Bower   今天自己用Angular写东西的时候,下载了Angular-seed项目,发现需要用到bower,之前也使用过,没有仔细了解,今天趁机了解到一些. bower的官网地址:  ...

  4. 胜利大逃亡[HDU1253]

    胜利大逃亡 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  5. MongoDB的安装与CRUD(JAVA)

    http://blogread.cn/it/article/4348?f=wb (MongoDB) 安装: 1)下载MongoDB数据库(这里使用Windows 32 bit版) http://dow ...

  6. wp 处理方法

    -DeepZoom:源于遥感影像的金字塔显示方式,提供了与高分辨率图像进行交互的能力,可以快速缩放图像而不影响应用的性能,加载或平移图像时可以光滑过度 -应用:高分辨率.极大图像的浏览,3D合成图像, ...

  7. [Cocos2d-x For WP8]Progress 进度条

    Cocos2d-x可以有多种进度条的展示方式,进度条的种类是根据进度条运动的方向来区分,包括顺时针,逆时针,从左到右,从右到左,从下到上和从上到下6种方式,这和WP8的进度条是由很大的区别的.那么Co ...

  8. 【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 lct: (ps:为嘛我的那么慢T_T,不知道排到哪了..难道别人都是树剖吗...看来有必要学 ...

  9. new在c#方法中的使用

    new在c#中有三种用法: 1.实例化对象 2.泛型约束 3.用在方法前.new和override的区别在于:override用于重写父类的方法:new用于隐藏方法,它调用的方法来自于申明的类,如果申 ...

  10. SpringMVC、Struts1、Struts2和SSH2框架中单例与多例的解析

    struts1是单例提供服务,请求数据绑定在actionform里,form当做参数传入调用方法,不用实例变量就不会出现并发问题. spring mvc的contrller也是这样的模式 struts ...