全面總結: Golang 調用 C/C++,例子式教程

做者:林冠宏 / 指尖下的幽靈c++

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8git

博客:http://www.cnblogs.com/linguanh/github

GitHub : https://github.com/af913337456/golang

大部分人學習或者使用某樣東西,喜歡在直觀上看到動手後的結果,纔會有繼續下去的興趣。

前言:

Golang 調用 C/C++ 的教程網上不少,就我目前所看到的,我的看法就是比較亂,坑也不少。但願本文能在必定程度上,作到更通俗明瞭。安全

下面 golang 簡稱 go , 一如既往,少說廢話,咱們如今開始。


go 調用 c/c++ 函數的實現方式有:

  • 直接嵌套在go文件中使用,最簡單直觀的
  • 導入動態庫 .so 或 dll 的形式,最安全可是很不爽也比較慢的
  • 直接引用 c/c++ 文件的形式,井井有條,容易隨時修改看結果的

第三個直接引用 c/c++ 文件的形式 是我要介紹的重點。ide

須要的環境支持

  • Linux 具有 gcc 與 g++ 便可
  • Windows 須要安裝 mingw,不然編譯時會有這類錯:cannot find -lmingwex
  • Mac 參考 Linux

1,直接嵌套在go文件

package main
/* // C 標誌io頭文件,你也可使用裏面提供的函數 #include <stdio.h> void pri(){ printf("hey"); } int add(int a,int b){ return a+b; } */
import "C"  // 切勿換行再寫這個

import "fmt"

func main() {
	fmt.Println(C.add(2, 1))
}
複製代碼

上面的代碼,直接拷貝運行就能輸出結果:3函數

結論:

  • 但凡要引用與 c/c++ 相關的內容,寫到 go 文件的頭部註釋裏面
  • 嵌套的 c/c++ 代碼必須符合其語法,不與 go 同樣
  • import "C" 這句話要緊隨,註釋後,不要換行,不然報錯
  • go 代碼中調用 c/c++ 的格式是: C.xxx(),例如 C.add(2, 1)

2,導入動態庫 .so 或 .dll 的形式

假設項目目錄以下

|-project
|  |-lib
|  |  |-libvideo.dll
|  |  |-libvideo.so
|  |-include
|  |  |-video.h
|  |-src
|  |  |-main.go
複製代碼

頭文件 .h 以下面這樣

//video.h
#ifndef VIDEO_H
#define VIDEO_H
void exeFFmpegCmd(char* cmd); // 聲明
#endif
複製代碼

源文件 .c 以下面這樣

#include <stdio.h>
#include "video.h"

void exeFFmpegCmd(char* cmd){ // 實現
    // ....
    printf("finish");
}
複製代碼

使用 gcc 或 g++ 生成 .so庫,或 win 下生成 dll

例如: gcc video.c -fPIC -shared -o libvideo.so學習

最後 main.go

把動態庫放到一個你喜歡的目錄,也能夠放到當前項目裏面,像上面列出的例子同樣。再引用ui

package main

/* #cgo CFLAGS: -Iinclude #cgo LDFLAGS: -Llib -llibvideo #include "video.h" */
import "C"

import "fmt"

func main() {
   cmd := C.CString("ffmpeg -i ./xxx/*.png ./xxx/yyy.mp4")
   C.exeFFmpegCmd(&cmd)
}
複製代碼

先回答爲何說這種是最安全的和最不爽的?緣由以下:

  • 動態庫破解十分困難,若是你的 go 代碼泄露,核心動態庫沒那麼容易被攻破
  • 動態庫會在被使用的時候被加載,影響速度
  • 操做難度比方式一麻煩很多

結論

  • CFLAGS: -I路徑 這句話指明頭文件所在路徑,-Iinclude 指明 當前項目根目錄的 include 文件夾
  • LDFLAGS: -L路徑 -l名字 指明動態庫的所在路徑,-Llib -llibvideo,指明在 lib 下面以及它的名字 video
  • 若是動態庫不存在,將會爆找不到定義之類的錯誤信息

3,直接引用 c/c++ 文件的形式 (重點)

假設項目目錄以下

|-util
|  |-util.h
|  |-util.c
|  |-util.go
複製代碼

util.h

int sum(int a,int b);
複製代碼

util.c

#include "util.h"
int sum(int a,int b){
    return (a+b);
}
複製代碼

util.go

package util

/* #include "util.c" */
import "C"

import "fmt"

func GoSum(a,b int) {
    s := C.sum(C.int(a),C.int(b))
    fmt.Println(s)
}
複製代碼

這樣調用 main.go

package main

func main(){
    util.GoSum(4,5)
}
複製代碼

第三種方式即是如此簡潔明瞭spa

最後,補充一下,通常須要 go 調用 c/c++ 的,主要是使用一些著名的開源庫,例如 ffmpegopencv,等這些源碼是基於 c/c++ 語言的,除此以外還有一個很重要的點,即是運行速度!

相關文章
相關標籤/搜索