標籤: 編譯器
c++makefile
struct
cfunction
2010-07-01 17:54
1875人閱讀收藏
舉報
技術(21)
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
#include
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<
if(dp==0)
cout<
//int(*f)(datetype* d);
funcdateptr f=(funcdateptr)dlsym(dp,"getdate2");
//void* test=dlsym(dp,"getdate");
//funcdate=(funcdate)funcdate;
error=dlerror();
if(error)
cout<
f(&d);
cout<
dlclose(dp);
return 0;
#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
/#include
#include
#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<
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(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!
頂 0 踩
solaris下的C編譯器
想簡單開發,少不了編譯器。沒辦法,上網搜尋了一下,大家都在說sun studio12,看了一下介面也挺漂亮的。雖然挺大的,安裝上去還得1g左右,還是下了下來。結果一堆得問題。首先就是,提示臨時資料夾空間不夠,剛開始沒好好看提示。還理解錯誤了。最後用.sunstudio12u1 sunos x86 p...
c 編譯器編譯過程
編譯過程 編譯過程分為四步 預處理 編譯 彙編 連線 1.預處理 預處理主要處理原始檔中的 include define 等預處理等命令 預處理主要完成的工作有 參考 程式設計師的自我修養 1 刪除 define,展開巨集 2 處理條件編譯指令。預處理程式先判斷條件,再根據條件修改源 3 刪除注釋 ...
Linux下gcc編譯器和g 編譯器的那些事兒
使用c c 程式設計大約有三四個年頭了。最開始涉及到微控制器 嵌入式linux等,都使用的是c語言,那時主要寫linux驅動,甚至在arm板上寫linux應用程式時需要應用物件導向的思想的時候,都是使用c語言的結構體和函式指標來實現。當然,使用的編譯器自然就是gcc了。後來,慢慢的轉向了使用c 編寫...