qt呼叫c語言函式庫 C 呼叫C語言的庫函式

2021-10-13 06:07:10 字數 3626 閱讀 1455

在專案中,使用c語言編寫了乙個socket後台程式tkcofferd,並且為方便客戶端的使用,提供了動態庫,其中包含socket介面。

現在的需求是使用qt做乙個前端介面,用來展示tkcofferd的socket介面功能,用於測試目的。

qt中使用c++語言編寫,如果需要呼叫tkcofferd的socket介面(由c語言編寫),需要指明函式匯出方式,詳述如下:

**c++呼叫c的庫函式時,如果標頭檔案定義得不恰當,可能會出現明明某函式在obj檔案中存在,但是卻發生鏈結失敗的情況,出現如下錯誤:

undefined reference to '***'

出現問題的原因是c庫函式編譯成obj檔案時對函式符號的處理和c++不同。因為c++函式支援過載,所以函式符號的處理要更複雜一些,c往往不作修飾。

例如有函式:

/*dofunc.c*/#include

intdofunc()

printf("dofunc\n");

使用gcc編譯成obj後

gcc -c dofunc.c

#生成 dofunc.o

objdump -x dofunc.o

[0](sec -2)(fl 0x00)(ty     0)(scl 103) (nx 1) 0x00000000 dofunc.c

file

[2](sec    1)(fl 0x00)(ty    20)(scl     2) (nx 1) 0x00000000 _dofunc

aux tagndx 0 ttlsiz 0x0 lnnos 0 next 0

[4](sec    1)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .text

aux scnlen 0x14 nreloc 2 nlnno 0

[6](sec    2)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .data

aux scnlen 0x0 nreloc 0 nlnno 0

[8](sec    3)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .bss

aux scnlen 0x0 nreloc 0 nlnno 0

[10](sec    4)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .rdata

aux scnlen 0x8 nreloc 0 nlnno 0

[12](sec    0)(fl 0x00)(ty    20)(scl     2) (nx 0) 0x00000000 _printf

c的dofunc函式在obj檔案裡的符號為 _dofunc

再看看使用g++編譯後的**:

g++ -c dofunc.c

objdump -x dofunc.o

symbol table:

[    0](sec -2)(fl 0x00)(ty     0)(scl 103) (nx 1) 0x00000000 dofunc.c

file

[    2](sec    1)(fl 0x00)(ty    20)(scl     2) (nx 1) 0x00000000 __z6dofuncv

aux tagndx 0 ttlsiz 0x0 lnnos 0 next 0

[    4](sec    1)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .text

aux scnlen 0x14 nreloc 2 nlnno 0

[    6](sec    2)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .data

aux scnlen 0x0 nreloc 0 nlnno 0

[    8](sec    3)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .bss

aux scnlen 0x0 nreloc 0 nlnno 0

[ 10](sec    4)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .rdata

aux scnlen 0x8 nreloc 0 nlnno 0

[ 12](sec    0)(fl 0x00)(ty    20)(scl     2) (nx 0) 0x00000000 _printf

g++編譯後的函式符號名比較古怪:__z6dofuncv

可見c和c++在加工函式名方面是很大不同的。

如果有c++程式要使用dofunc.o ,如下程式的函式宣告是錯的

//main_dev.cpp

intdofunc();int main(int argc , char*args)

dofunc();

system("pause");

g++  -o main_dev main_dev.cpp dofunc.o

main_dev.cpp: undefined reference to `dofunc()'

collect2: ld returned 1 exit status

原因是dofunc函式在加工後函式名應該為__z6dofuncv ,dofunc.o檔案裡面的是_dofunc,所以找不到。

如果有dofunc的源**,解決辦法很簡單,將dofunc.c使用c++來編譯即可。

如果不幸地dofunc函式在別人的庫裡面,而這個庫是用c編寫和gcc編譯的,源**不可見,那怎麼辦呢?

幸虧c++和編譯器的設計者早已料到了這個問題,並提供了一種通用的解決辦法:使用extern "c"來修飾舊c庫的外部函式宣告。

1 extern "c"4

5 int main(int argc , char*args)6

g++  -o main_dev main_dev.cpp dofunc.o

成功extern "c"修飾內的函式,一律按照c的風格來編譯,以便能夠鏈結到用c編譯出來的obj庫上去。

常見有形如:

#ifdef __cplusplu***tern "c"#endif

這種的標頭檔案一般是庫開發者提供的,能同時被c和c++模組使用。巨集__cplusplus 是c++編譯器定義的,這種寫法保證了用c++編譯時extern "c" 能生效;而用c編譯時又不會因不會處理extern  "c"而錯誤。

反過來,如果c需要呼叫c++編譯的庫又怎麼辦呢?相信一般情況下不會有這樣奇特的要求,直接用c++編譯不就完了?

把main_dev.cpp改名為main.c ,然後

gcc  -o main_dev main_dev.c dofunc.o

當然會出現: undefined reference to `dofunc'

1 //main_dev.c

2 int (*dofunc)(); /*宣告函式指標*/

3 int _z6dofuncv(); /*會鏈結到 __z6dofuncv*/

5 int main(int argc , char*args)6

gcc  -o main_dev main_dev.c dofunc.o

成功上面講了那麼多,中心意思都是c和c++編譯和鏈結時對函式名加工的細節問題,理解了這些細節後,如何運用完全就存乎一心了。

C語言函式庫

從今天開始,慢慢的寫全c語言函式庫的函式使用 1.函式名 atoi 功 能 把字串轉換成長整型數 用 法 int atoi const char nptr 需要傳進乙個char型別的指標 程式例 include include int main void 2.abort 功 能 異常終止乙個程序 用...

C 中呼叫 C靜態函式庫的方法

c 中呼叫 c靜態函式庫的方法 首先,編寫靜態庫函式 player.h ifndef player h define player h void player open char path endif player.c include player.h include void player ope...

c語言呼叫cpp函式 C語言 函式的遞迴呼叫

乙個函式在呼叫的過程 現直接或者間接呼叫該函式本身的情況,稱為遞迴呼叫,這種函式稱為遞迴函式 在寫遞迴函式時,需要解決如下兩個問題 1 遞迴的出口條件 2 遞迴公式 遞迴函式的 一般為 if 遞迴出口條件 返回符合出口條件的函式值或輸出結果 else 遞迴公式 雖然演算法一致,但n不同,y不同,在記...