Golang 调用 C/C++,例子式教程
程序员文章站
2022-11-01 16:19:35
大部分人学习或者使用某样东西,喜欢在直观上看到动手后的结果,才会有继续下去的兴趣。 前言: Golang 调用 C/C++ 的教程网上很多,就我目前所看到的,个人见解就是比较乱,坑也很多。希望本文能在一定程度上,做到更通俗明了。 下面 golang 简称 go , 一如既往,少说废话,我们现在开始。 ......
大部分人学习或者使用某样东西,喜欢在直观上看到动手后的结果,才会有继续下去的兴趣。
前言:
golang 调用 c/c++ 的教程网上很多,就我目前所看到的,个人见解就是比较乱,坑也很多。希望本文能在一定程度上,做到更通俗明了。
下面 golang 简称 go , 一如既往,少说废话,我们现在开始。
go 调用 c/c++ 函数的实现方式有:
- 直接
嵌套
在go文件中使用,最简单直观的 - 导入
动态库 .so 或 dll
的形式,最安全但是很不爽也比较慢的 - 直接引用 c/c++ 文件的形式,层次分明,容易随时修改看结果的
第三个直接引用 c/c++ 文件的形式
是我要介绍的重点。
需要的环境支持
- linux 具备 gcc 与 g++ 即可
- windows 需要安装 ,否则编译时会有这类错:
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++ 语言的,除此之外还有一个很重要的点,便是运行速度!
完
上一篇: 爆笑的炫富和炫耀
下一篇: 唐太宗李世民,在中国历史上是什么地位?