在C++编译器下dlsym()引发的思考
来源:互联网 发布:大数据征信查询入口 编辑:程序博客网 时间:2024/05/16 10:59
在C++编译器下dlsym()引发的思考
cafesun 2007-02-16
这几天看到讲解dlopen,dlsym函数的文章,忍不住自己编码尝试了一下。引出了一些其他知识。
dlsym()的函数原型是
void* dlsym(void* handle,const char* symbol)
handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数的名称,函数返回值是void*,指向函数的地址,供调用使用。dlsym的返回值与symbol参数就是本文着重要讲述的要点。
先看下面一段代码
////////////////////////////////DLLTest.cpp//////////////////////////////////////////////////////
#include "DateTime.h"
#include <dlfcn.h>
#include <iostream>
using namespace std;
typedef int(*FuncDatePtr)(DateType* d);
int main(int argc,char* argv[])
{
DateType d;
//TimeType t;
void* dp=0;
char* error=0;
cout<<"Dll Programe Demo:"<<endl;
dp=dlopen("libtime.so",RTLD_NOW);
if(dp==0)
{
cout<<"Open time.so Failed!"<<dlerror()<<endl;
return 1;
}
//int(*f)(DateType* d);
FuncDatePtr f=(FuncDatePtr)dlsym(dp,"getdate2");
//void* test=dlsym(dp,"getdate");
//funcDate=(FuncDate)funcDate;
error=dlerror();
if(error)
{
cout<<"ERROR:"<<error<<endl;
return 1;
}
f(&d);
cout<<"Today Year="<<d.year<<endl;
dlclose(dp);
return 0;
}
//////////////////DateTime.h/////////////////////////
#ifndef DATETIME_H_
#define DATETIME_H_
#ifdef __cplusplus
extern "C"{
#endif
struct DateType
{
int year;
int month;
int day;
};
struct TimeType
{
int hour;
int minute;
int second;
};
int getdate2(DateType* d);
int gettime2(TimeType* t);
#ifdef __cplusplus
}
#endif
///////////////////////////////////////DateTime.cpp////////////////////////////////////////////////////
#include <time.h>
#include <iostream>
#include "DateTime.h"
using namespace std;
int getdate2(DateType* d)
{
long ti;
struct tm *tm;
time(&ti);
tm=localtime(&ti);
d->year=tm->tm_year+1900;
d->month=tm->tm_mon+1;
d->day=tm->tm_mday;
cout<<"function getdate() loaded!"<<endl;
return 0;
}
int gettime2(TimeType* t)
{
long ti;
struct tm *tm;
time(&ti);
tm=localtime(&ti);
t->hour=tm->tm_hour;
t->minute=tm->tm_min;
t->second=tm->tm_sec;
return 0;
}
DateTime.h,DateTime.cpp两个文件主要包含两个函数getdate2,gettime2(为什么函数名如此,在下面会专门提到)生成了动态链接库libtime.so。DLLTest.cpp中的逻辑就是打开libtime.so这个文件,然后取getdate2函数,并调用它。
第一个要讲的就是 FuncDatePtr f=(FuncDatePtr)dlsym(dp,"getdate2");这个地方。看似简单的一个指针强制转换,实际上并不是那么简单,这里的指针转换不同于一般的指针转换,实际上是将一个指向对象的指针转换为指向函数的指针,这里除了使用传统的强制转换方式,还可以使用C++自带的reinterpret_cast转换符,可以这样写:
void* vf=dlsym(dp,"getdate2");
FuncDatePtr f=reinterpret_cast<FuncDatePtr>(vf);
这个转换只在C++中需要,因而也只在C++中遇到这个问题。
第二点要讲的是DateTime.h中的
#ifdef __cplusplus
extern "C"{
#endif
......
#ifdef __cplusplus
}
#endif
为什么一定要定义这样的宏呢,如果不定义会怎么样,也许很多人(包括我以前)也会这样问。既然有这样的疑问,那一切以实例说话,我去掉这个地方extern “C”的声明,看看编译的程序运行起来会怎么样......
稍作修改后,DllTest依然可以编译,无甚特别的。但运行一下呢?喔喔,怎么老是报错“Error:No Error”?Error是我代码里面定义的输出,那个No Error是dlerror返回的字符串。说是No Error,其实还是有错的,只是错不在dlsym(),而是错在我这里。
可以返回去重新看看那段代码
FuncDatePtr f=(FuncDatePtr)dlsym(dp,"getdate2");
如果你一眼看出问题了,那下面要讲的内容,你可以不看了。如果3分钟内没有发现问题,那么还是听我罗嗦一下。大家肯定听说过C++有Name Mangling机制吧(没有听说的话,可以查看一下Lippman的《深入探索C++对象模型》)。当我去掉了extern “C”的时候,就注定会跌入这个陷阱。我用的g++编译的库文件,g++自然的运用了Name Mangling技术,原本的getdate(DateType& d)函数,很有可能其名字已变成了_getdate_DateType(DateType& d)这样(不同的编译器实现不一样),而对于引用dlsym这样的纯C编译好的库中的函数,他们对Name Mangling机制无甚了解,不会有智能的转换,所以它在C++编译器下不会自动的去作名字处理,当我传入getdate2作为symbol参数的时候,dlsym自然是找不到对应的函数地址的。但他自己又没啥错,就丢给我一串“No Error”。
到了这里,了解没有extern “C”会发生什么事情,并且了解了原因后,我们可以转回来。extern “C”起了什么作用,大家心里应该都清楚了。我懒得引用官方正式的解释了,虽然定义的很完善,但我觉得很挠口,很难懂。所以我把我自己的理解帖出来,不怕大家见笑。
extern “C“就是告诉C++编译器,到了这里要用C编译器的方式来编译,不要什么Name Mangling之类的高科技了。细致的从语法上分析,有两层含义,但同样讲得也是这个意思。
-
extern 关键字声明被修饰的对象可供其他模块调用(这里乱盖一下,可能被乱砖砸晕。我试着用GCC编译了一下,在C编译器下,如果函数被extern修饰,其他模块引用该函数,可以不包含该模块的头文件的)
-
“C”,告诉C++编译器,这里用C的标准编译。
好了,dlsym引出的问题一一解决了,这里提醒各位,在编译的时候,最好加上-ldl参数。至于makefile,我想大家都有(或者不需要makefile),编译的问题,我就不罗嗦了。Over!
- 在C++编译器下dlsym()引发的思考
- [转]在C++编译器下dlsym()引发的思考
- 在C++编译器下dlsym()引发的思考
- 转]在C++编译器下dlsym()引发的思考
- 一道C面试题引发的思考
- C语言sizeof引发的思考
- C语言除0引发的思考
- 由“标准C”“纯C”引发的思考
- 关于C和C++编译器引发的一系列问题
- Yaffs引发的思考
- LPCSTR引发的思考
- IllegalAccessError引发的思考
- 离职引发的思考
- 脚本引发的思考
- 面试引发的思考
- PHP_EOL引发的思考
- free 引发的思考
- 快播案引发的思考
- 通过分层来体现 "有一个" 或 "用...来实现"
- Single-Row Functions
- 非常有用的window知识
- 架设freeradius+mysql的radius服务器
- 批量文件重命名器BatchRename程序
- 在C++编译器下dlsym()引发的思考
- 走过2006-阳光总在风雨后
- 自动设置WindowsIP的程序SetupIP
- Emacs入门技巧: 排错
- 区分继承和模板
- 春节快乐!
- C++ include预处理指示符
- Rapidshare-video-tutorial
- Special Edition Using Oracle 11i