专栏首页林冠宏的技术文章全面总结: Golang 调用 C/C++,例子式教程

全面总结: Golang 调用 C/C++,例子式教程

作者:林冠宏 / 指尖下的幽灵

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

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

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

大部分人学习或者使用某样东西,喜欢在直观上看到动手后的结果,才会有继续下去的兴趣。

前言:

Golang 调用 C/C++ 的教程网上很多,就我目前所看到的,个人见解就是比较乱,坑也很多。希望本文能在一定程度上,做到更通俗明了。

下面 golang 简称 go , 一如既往,少说废话,我们现在开始。


go 调用 c/c++ 函数的实现方式有:

  • 直接嵌套在go文件中使用,最简单直观的
  • 导入动态库 .so 或 dll 的形式,最安全但是很不爽也比较慢的
  • 直接引用 c/c++ 文件的形式,层次分明,容易随时修改看结果的

第三个直接引用 c/c++ 文件的形式 是我要介绍的重点。

需要的环境支持

  • 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

把动态库放到一个你喜欢的目录,也可以放到当前项目里面,像上面列出的例子一样。再引用

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++ 的,主要是使用一些著名的开源库,例如 ffmpegopencv,等这些源码是基于 c/c++ 语言的,除此之外还有一个很重要的点,便是运行速度!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 全面总结: Golang 调用 C/C++,例子式教程

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:htt...

    林冠宏-指尖下的幽灵
  • 2017了,回家前 "年末" 分享:下雨,飘雪,红包雨,碰撞球,自定义View

    (本博客为原创:https://cloud.tencent.com/developer/user/1148436/activities) 目录:   效果展示 ...

    林冠宏-指尖下的幽灵
  • Golang:线程 和 协程 的区别

    国庆越快各位,距离上次发文快两个月了,19年也快结束了。现在的总结更多是放在了草稿 而没有发出,这次详细分享下在 Go 中,线程和协程的区别及其关系。

    林冠宏-指尖下的幽灵
  • 全面总结: Golang 调用 C/C++,例子式教程

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:htt...

    林冠宏-指尖下的幽灵
  • 关于Java并发编程的总结和思考

    编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的...

    Java团长
  • POJ 1581 优先队列 priority_queue -- 比赛胜者求解

    给定选手姓名,及答题提交次数(提交正确前,错误一次罚20分),每题的做题时间罚分(未正确作答的不罚分),最后求谁是胜出者(优先条件,答对题目多,次要条件,总罚分...

    Michael阿明
  • GO语言学习笔记

    rectinajh
  • Android 滑动效果进阶篇(六)—— 倒影效果

    上篇介绍了使用Animation实现3D动画旋转翻页效果,现在介绍图片倒影实现,先看效果图

    阳光岛主
  • uni-app实现多端开发

    多端开发,听名字就感觉不一样,一套代码。多端使用,适用于各个平台。市面上很多关于多端开发的框架,比较常用,流行的框架 uni-app,Chameleon(变色龙...

    小周sri的码农
  • JAVA入门学习二

    循环结构分类:for / while / do…while 跳出循环:break; [ 只能在switch和循环中 ] 继续执行:continue; [ 只能在...

    WeiyiGeek

扫码关注云+社区

领取腾讯云代金券