大部分人学习或者使用某样东西, 喜欢在直观上看到动手后的结果, 才会有继续下去的兴趣.
前言:
Golang 调用 C/C++ 的教程网上很多, 就我目前所看到的, 个人见解就是比较乱, 坑也很多. 希望本文能在一定程度上, 做到更通俗明了.
下面 golang 简称 go , 一如既往, 少说废话, 我们现在开始.
go 调用 c/c++ 函数的实现方式有:
直接嵌套在 go 文件中使用, 最简单直观的
导入
动态库 .so 或 dll
的形式, 最安全但是很不爽也比较慢的
直接引用 c/c++ 文件的形式, 层次分明, 容易随时修改看结果的
第三个直接引用 c/c++ 文件的形式 是我要介绍的重点.
需要的环境支持
Linux 具备 gcc 与 g++ 即可
Windows 需要安装 http://www.mingw.org/ , 否则编译时会有这类错:
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
把动态库放到一个你喜欢的目录, 也可以放到当前项目里面, 像上面列出的例子一样. 再引用
- 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) int {
- s := C.sum(C.int(a),C.int(b))
- fmt.Println(s)
- }
这样调用 main.go
- package main
- func main(){
- util.GoSum(4,5)
- }
第三种方式便是如此简洁明了.
最后, 补充一下, 一般需要 go 调用 c/c++ 的, 主要是使用一些著名的开源库, 例如 FFMPEG,opencv, 等这些源码是基于 c/c++ 语言的, 除此之外还有一个很重要的点, 便是运行速度!
完
来源: http://www.bubuko.com/infodetail-3201792.html