一般C語言寫的程序可以讓其他語言進(jìn)行調(diào)用,比如python, java,等等
成都創(chuàng)新互聯(lián)公司2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元舟山做網(wǎng)站,已為上家服務(wù),為舟山各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220
c語言有兩種庫類型,靜態(tài)庫和動(dòng)態(tài)庫(共享庫)
命令:ar rcs libmulib.a file1.o
1.靜態(tài)鏈接庫
打開VS2010,新建一個(gè)項(xiàng)目,選擇win32項(xiàng)目,點(diǎn)擊確定,選擇靜態(tài)庫這個(gè)選項(xiàng),預(yù)編譯頭文件可選可不選。
在這個(gè)空項(xiàng)目中,添加一個(gè).h文件和一個(gè).cpp文件。名字我們起為static.h和static.cpp
static.h文件:
[cpp]?view plaincopy
#ifndef?LIB_H
#define?LIB_H
extern?"C"?int?sum(int?a,int?b);
#endif
static.cpp文件:
[cpp]?view plaincopy
#include?"static.h"
int?sum(int?a,int?b)
{
return?a+b;
}
編譯這個(gè)項(xiàng)目之后,會(huì)在debug文件夾下生成static.lib文件,這個(gè)就是我們需要的靜態(tài)鏈接庫。
下面說明如何調(diào)用靜態(tài)鏈接庫。
首先需要新建一個(gè)空項(xiàng)目,起名為test。將之前static項(xiàng)目下的static.h和static.lib這個(gè)2個(gè)文件復(fù)制到test項(xiàng)目的目錄下,并在工程中加入static.h文件。
新建一個(gè)test.cpp文件如下:
[cpp]?view plaincopy
#include?stdio.h
#include?stdlib.h
#include?"static.h"
#pragma?comment(lib,"static.lib")
int?main()
{
printf("%d\n",sum(1,2));
system("pause");
return?0;
}
編譯運(yùn)行可得結(jié)果:3
#pragma comment(lib,"static.lib"),這一句是顯式的導(dǎo)入靜態(tài)鏈接庫。除此之外,還有其他的方法,比如通過設(shè)置路徑等等,這里不做介紹。
2.動(dòng)態(tài)鏈接庫
和創(chuàng)建靜態(tài)鏈接庫一樣,需要?jiǎng)?chuàng)建一個(gè)空的win32項(xiàng)目,選擇dll選項(xiàng)。創(chuàng)建dynamic.cpp和dynamic.h文件
dynamic.h文件:
[cpp]?view plaincopy
#ifndef?DYNAMIC
#define?DYNAMIC
extern?"C"?__declspec(dllexport)int?sum(int?a,?int?b);
#endif?DYNAMIC
dynamic.cpp文件:
[cpp]?view plaincopy
#include?"dynamic.h"
int?sum(int?a,?int?b)
{
return?a+b;
}
編譯這個(gè)項(xiàng)目,會(huì)在debug文件夾下生成dynamic.dll文件。
下面介紹如何調(diào)用動(dòng)態(tài)鏈接庫,這里講的是顯式的調(diào)用。
在剛才的test項(xiàng)目下,把static.lib和static.h文件刪除,把dynamic.h和dynamic.dll復(fù)制到該目錄下,并在項(xiàng)目中添加dynamic.h文件,修改test.cpp文件為:
[cpp]?view plaincopy
#include?stdio.h
#include?stdlib.h
#includeWindows.h
#include?"dynamic.h"
int?main()
{
HINSTANCE?hDll=NULL;
typedef?int(*PSUM)(int?a,int?b);
PSUM?pSum;
hDll?=?LoadLibrary(L"dynamic.dll");
pSum?=?(PSUM)GetProcAddress(hDll,"sum");
printf("%d\n",pSum(1,2));
system("pause");
FreeLibrary(hDll);
return?0;
}
編譯運(yùn)行結(jié)果為:3
特別提示:
1.extern "C"中的C是大寫,不是小寫
2.如果從VS2010中直接運(yùn)行程序,lib和dll需要放到test項(xiàng)目的目錄下;如果想雙擊項(xiàng)目test下的debug文件中的exe文件直接運(yùn)行的話,需把lib和dll放入debug文件夾下。
之所以成為【靜態(tài)庫】,是因?yàn)樵阪溄与A段,會(huì)將匯編生成的目標(biāo)文件.o與引用到的庫一起鏈接打包到可執(zhí)行文件中。因此對(duì)應(yīng)的鏈接方式稱為靜態(tài)鏈接。
試想一下,靜態(tài)庫與匯編生成的目標(biāo)文件一起鏈接為可執(zhí)行文件,那么靜態(tài)庫必定跟.o文件格式相似。其實(shí)一個(gè)靜態(tài)庫可以簡(jiǎn)單看成是一組目標(biāo)文件(.o/.obj文件)的集合,即很多目標(biāo)文件經(jīng)過壓縮打包后形成的一個(gè)文件。靜態(tài)庫特點(diǎn)總結(jié):
為什么需要?jiǎng)討B(tài)庫,其實(shí)也是靜態(tài)庫的特點(diǎn)導(dǎo)致。
動(dòng)態(tài)庫特點(diǎn)總結(jié):
生成動(dòng)態(tài)庫
應(yīng)該編譯成.a文件
ar rc c:\libab.a c:\a.o c:\b.o
然后,再編譯執(zhí)行文件
gcc -o c:\m.exe c:\m.c -LC:\ -lab
你這樣試試
Cgo 使得Go程序能夠調(diào)用C代碼. cgo讀入一個(gè)用特別的格式寫的Go語言源文件, 輸出Go和C程序, 使得C程序能打包到Go語言的程序包中.
舉例說明一下. 下面是一個(gè)Go語言包, 包含了兩個(gè)函數(shù) -- Random 和 Seed -- 是C語言庫中random和srandom函數(shù)的馬甲.
package rand
/*
#include stdlib.h
*/ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }
我們來看一下這里都有什么內(nèi)容. 開始是一個(gè)包的導(dǎo)入語句.
rand包導(dǎo)入了"C"包, 但你會(huì)發(fā)現(xiàn)在Go的標(biāo)準(zhǔn)庫里沒有這個(gè)包. 那是因?yàn)镃是一個(gè)"偽包", 一個(gè)為cgo引入的特殊的包名, 它是C命名空間的一個(gè)引用.
rand 包包含4個(gè)到C包的引用: 調(diào)用 C.random和C.srandom, 類型轉(zhuǎn)換 C.uint(i)還有引用語句.
Random函數(shù)調(diào)用libc中的random函數(shù), 然后回返結(jié)果. 在C中, random返回一個(gè)C類型的長(zhǎng)整形值, cgo把它輪換為C.long. 這個(gè)值必需轉(zhuǎn)換成Go的類型, 才能在Go程序中使用. 使用一個(gè)常見的Go類型轉(zhuǎn)換:
func Random() int { return int(C.random()) }
這是一個(gè)等價(jià)的函數(shù), 使用了一個(gè)臨時(shí)變量來進(jìn)行類型轉(zhuǎn)換:
func Random() int { var r C.long = C.random() return int(r) }
Seed函數(shù)則相反. 它接受一個(gè)Go語言的int類型, 轉(zhuǎn)換成C語言的unsigned int類型, 然后傳遞給C的srandom函數(shù).
func Seed(i int) { C.srandom(C.uint(i)) }
需要注意的是, cgo中的unsigned int類型寫為C.uint; cgo的文檔中有完整的類型列表.
這個(gè)例子中還有一個(gè)細(xì)節(jié)我們沒有說到, 那就是導(dǎo)入語句上面的注釋.
/*
#include stdlib.h
*/ import "C"
Cgo可以識(shí)別這個(gè)注釋, 并在編譯C語言程序的時(shí)候?qū)⑺?dāng)作一個(gè)頭文件來處理. 在這個(gè)例子中, 它只是一個(gè)include語句, 然而其實(shí)它可以是使用有效的C語言代碼. 這個(gè)注釋必需緊靠在import "C"這個(gè)語句的上面, 不能有空行, 就像是文檔注釋一樣.
Strings and things
與Go語言不同, C語言中沒有顯式的字符串類型. 字符串在C語言中是一個(gè)以0結(jié)尾的字符數(shù)組.
Go和C語言中的字符串轉(zhuǎn)換是通過C.CString, C.GoString,和C.GoStringN這些函數(shù)進(jìn)行的. 這些轉(zhuǎn)換將得到字符串類型的一個(gè)副本.
下一個(gè)例子是實(shí)現(xiàn)一個(gè)Print函數(shù), 它使用C標(biāo)準(zhǔn)庫中的fputs函數(shù)把一個(gè)字符串寫到標(biāo)準(zhǔn)輸出上:
package print // #include stdio.h // #include stdlib.h import "C" import "unsafe" func Print(s string) { cs := C.CString(s) C.fputs(cs, (*C.FILE)(C.stdout)) C.free(unsafe.Pointer(cs)) }
在C程序中進(jìn)行的內(nèi)存分配是不能被Go語言的內(nèi)存管理器感知的. 當(dāng)你使用C.CString創(chuàng)建一個(gè)C字符串時(shí)(或者其它類型的C語言內(nèi)存分配), 你必需記得在使用完后用C.free來釋放它.
調(diào)用C.CString將返回一個(gè)指向字符數(shù)組開始處的指錯(cuò), 所以在函數(shù)退出前我們把它轉(zhuǎn)換成一個(gè)unsafe.Pointer(Go中與C的void 等價(jià)的東西), 使用C.free來釋放分配的內(nèi)存. 一個(gè)慣用法是在分配內(nèi)存后緊跟一個(gè)defer(特別是當(dāng)這段代碼比較復(fù)雜的時(shí)候), 這樣我們就有了下面這個(gè)Print函數(shù):
func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) }
構(gòu)建 cgo 包
如果你使用goinstall, 構(gòu)建cgo包就比較容易了, 只要調(diào)用像平常一樣使用goinstall命令, 它就能自動(dòng)識(shí)別這個(gè)特殊的import "C", 然后自動(dòng)使用cgo來編譯這些文件.
如果你想使用Go的Makefiles來構(gòu)建, 那在CGOFILES變量中列出那些要用cgo處理的文件, 就像GOFILES變量包含一般的Go源文件一樣.
rand包的Makefile可以寫成下面這樣:
include $(GOROOT)/src/Make.inc
TARG=goblog/rand
CGOFILES=\ rand.go\ include $(GOROOT)/src/Make.pkg
然后輸入gomake開始構(gòu)建.
更多 cgo 的資源
cgo的文檔中包含了關(guān)于C偽包的更多詳細(xì)的說明, 以及構(gòu)建過程. Go代碼樹中的cgo的例子給出了更多更高級(jí)的用法.
一個(gè)簡(jiǎn)單而又符合Go慣用法的基于cgo的包是Russ Cox寫的gosqlite. 而Go語言的網(wǎng)站上也列出了更多的的cgo包.
最后, 如果你對(duì)于cgo的內(nèi)部是怎么運(yùn)作這個(gè)事情感到好奇的話, 去看看運(yùn)行時(shí)包的cgocall.c文件的注釋吧.
你通過VS調(diào)試運(yùn)行程序的時(shí)候默認(rèn)會(huì)去查找程序目錄下面的Debug中的和項(xiàng)目同名的exe文件(你的情況是TEST.exe)。因?yàn)槟憔幾g失敗了,exe文件沒有生成所以找不到這個(gè)文件去執(zhí)行。你目前的情況看來是你嘗試用C的編譯器去編譯C++代碼(因?yàn)槟銊?chuàng)建的是.c文件)所以失敗。把文件名改成cpp重新編譯再試