關(guān)鍵是 lpOnRecvCardEvent 這個(gè)函數(shù)的第二個(gè)參數(shù)是個(gè) C++ 指針。 樓主在 C# 中聲明這個(gè)導(dǎo)出函數(shù)時(shí),使用了并不對應(yīng)的 CardEvent[] C# 數(shù)組類型。 正確的做法是: 在 C# 聲明 lpOnRecvCardEvent 時(shí),第二個(gè)參數(shù)應(yīng)該是 IntPtr ,不是數(shù)組。 由于樓...
創(chuàng)新互聯(lián)專注于下陸網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供下陸營銷型網(wǎng)站建設(shè),下陸網(wǎng)站制作、下陸網(wǎng)頁設(shè)計(jì)、下陸網(wǎng)站官網(wǎng)定制、小程序設(shè)計(jì)服務(wù),打造下陸網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供下陸網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
直接嵌入c源代碼到go代碼里面
package main
/*
#include stdio.h
void myhello(int i) {
printf("Hello C: %d\n", i);
}
*/
import "C"
import "fmt"
func main() {
C.myhello(C.int(12))
fmt.Println("Hello Go");
}
需要注意的是C代碼必須放在注釋里面
import "C"語句和前面的C代碼之間不能有空行
運(yùn)行結(jié)果
$ go build main.go ./main
Hello C: 12
Hello Go
分開c代碼到單獨(dú)文件
嵌在一起代碼結(jié)構(gòu)不是很好看,很多人包括我,還是喜歡把兩個(gè)分開,放在不同的文件里面,顯得干凈,go源文件里面是go的源代碼,c源文件里面是c的源代碼。
$ ls
hello.c hello.h main.go
$ cat hello.h
void hello(int);
$ cat hello.c
#include stdio.h
void hello(int i) {
printf("Hello C: %d\n", i);
}
$ cat main.go
package main
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
編譯運(yùn)行
$ go build ./main
Hello C: 12
Hello Go
編譯成庫文件
如果c文件比較多,最好還是能夠編譯成一個(gè)獨(dú)立的庫文件,然后go來調(diào)用庫。
$ find mylib main
mylib
mylib/hello.h
mylib/hello.c
main
main/main.go
編譯庫文件
$ cd mylib
# gcc -fPIC -shared -o libhello.so hello.c
編譯go程序
$ cd main
$ cat main.go
package main
// #cgo CFLAGS: -I../mylib
// #cgo LDFLAGS: -L../mylib -lhello
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
$ go build main.go
運(yùn)行
$ export LD_LIBRARY_PATH=../mylib
$ ./main
Hello C: 12
Hello Go
在我們的例子中,庫文件是編譯成動(dòng)態(tài)庫的,main程序鏈接的時(shí)候也是采用的動(dòng)態(tài)庫
$ ldd main
linux-vdso.so.1 = (0x00007fffc7968000)
libhello.so = ../mylib/libhello.so (0x00007f513684c000)
libpthread.so.0 = /lib64/libpthread.so.0 (0x00007f5136614000)
libc.so.6 = /lib64/libc.so.6 (0x00007f5136253000)
/lib64/ld-linux-x86-64.so.2 (0x000055d819227000)
理論上講也是可以編譯成整個(gè)一靜態(tài)鏈接的可執(zhí)行程序,由于我的機(jī)器上缺少靜態(tài)鏈接的系統(tǒng)庫,比如libc.a,所以只能編譯成動(dòng)態(tài)鏈接。
默認(rèn)是動(dòng)態(tài)鏈接了glibc,但你也可以通過編譯選項(xiàng)改成靜態(tài)鏈接或者使用純go庫。
GO語言包估計(jì)能直接調(diào)用我沒試
編譯DLL庫絕調(diào)用或者直接直接用系統(tǒng)命令調(diào)用編譯完執(zhí)行程序
由于我們的 Dockerfile 使用多階段構(gòu)建,
由于 alpine 鏡像非常小,只有 5 mb 左右,但是由于客戶那邊強(qiáng)制要使用紅帽的基礎(chǔ)鏡像,所以在第二階段修改成紅帽的鏡像,最終打成的鏡像運(yùn)行的時(shí)候會(huì)提示 No such file or directory 。
這個(gè)問題的原因在于第一階段構(gòu)建的環(huán)境和第二階段的運(yùn)行的環(huán)境不一致,很多時(shí)候以為都是 Linux 環(huán)境,怎么可能不一致呢,但是由于 Linux 的各個(gè)發(fā)行版都有自己定制化的部分,就譬如 alpine 分支,他的 C 語言動(dòng)態(tài)鏈接庫使用的是 musl,而像 centos 用的都是 glibc,他們都是 c 語言的標(biāo)準(zhǔn)庫,用來調(diào)用操作系統(tǒng)的庫。
上面說的是一方面原因,但是不是這個(gè)問題的最具體的原因。
go build 打包出來的二進(jìn)制文件還寫一個(gè)非常重要的信息 interpreter 。
我將二進(jìn)制文件從容器內(nèi) copy 出來通過 file 查看
可以看到二進(jìn)制的文件上有些一個(gè)解釋器的地址,這個(gè)文件地址是寫死在二進(jìn)制文件上的,后面我啟動(dòng)一個(gè) centos 容器。
果然報(bào)了同樣的一個(gè)錯(cuò)誤。
Linux 如何啟動(dòng)一個(gè)二進(jìn)制文件可以參考一下參考文檔,就是通過這個(gè)解釋器出發(fā)將程序調(diào)入內(nèi)存。
工程結(jié)構(gòu)如上圖所示,我們需要實(shí)現(xiàn)的目標(biāo)是在go文件中調(diào)用c文件
foo.c如下:
foo.go如下
foo.h如下:
編譯過程如下:
1、先將c文件編譯為.o文件,然后生成動(dòng)態(tài)鏈接庫.dylib文件
(1) clang -c foo.c
(2 clang -shared foo.o -o libfoo.dylib
2、在上述的動(dòng)態(tài)鏈接庫生成之后,在foo.go中添加動(dòng)態(tài)鏈接命令:#cgo LDFLAGS: -L./ -lfoo
需要注意的是
中間不能有空格