cgo的踩坑记及一个简单的例子

1. 对照表

首先,来看 golang 和 C 的类型转换对照表:

C语言类型CGO类型Go语言类型
charC.charbyte
singed charC.scharint8
unsigned charC.ucharuint8
shortC.shortint16
unsigned shortC.ushortuint16
intC.intint32
unsigned intC.uintuint32
longC.longint32
unsigned longC.ulonguint32
long long intC.longlongint64
unsigned long long intC.ulonglonguint64
floatC.floatfloat32
doubleC.doublefloat64
size_tC.size_tuint

值得注意的是,C 中的整形比如 int 在标准中是没有定义具体字长的,但一般默认认为是 4 字节,对应 CGO 类型中 C.int 则明确定义了字长是 4 ,但 golang 中的 int 字长则是 8 ,因此对应的 golang 类型不是 int 而是 int32 。为了避免误用,C 代码最好使用 C99 标准的数值类型,对应的转换关系如下:

C语言类型CGO类型Go语言类型
int8_tC.int8_tint8
uint8_tC.uint8_tuint8
int16_tC.int16_tint16
uint16_tC.uint16_tuint16
int32_tC.int32_tint32
uint32_tC.uint32_tuint32
int64_tC.int64_tint64
uint64_tC.uint64_tuint64

2. 隐藏的坑

在Go中调用C一共有两种办法:

  • 第一种是将C代码直接嵌入到GO源文件中
  • 第二种是将C代码写在C文件中,再在GO文件中引入

2.1 嵌入式

第一种实现起来比较顺滑,如丝一般,但是没有进行分文件夹管理,看上去很不爽,同时也隐藏了一个坑,直接看一个栗子:

package main

/*
#include <stdio.h>

static int32_t add(int32_t a, int32_t b){
  return a+b;
}
*/
import "C"
import "fmt"

func main() {
  var a, b int32 = 1, 2
  c := int32(C.add(C.int32_t(a), C.int32_t(b)))
  fmt.Println(c)
}

如果在c代码与“import “C””之间留一个空行,直接报错如下:
在这里插入图片描述
去掉空行后就ok啦~,结果如下:
在这里插入图片描述

2.2 独立式

第二种实现实现起来坑就大大的了,no bb, 直接上栗子:
在这里插入图片描述

//foo.c
#include <stdio.h>

//int count = 6;
void foo() {
    printf("I am foo!\n");
}
//foo.h

int count = 6;
void foo();
package main

// #include <stdio.h>
// #include <stdlib.h>
// #include "foo.h"
import "C"
import "fmt"

func main() {
  fmt.Println(C.count)
  C.foo()
}

佛曰:众生都是这么干的,一般分为两步:

但在第二步的编译过程中会出现如下“对foo未定义的引用“的错误:
在这里插入图片描述
于是乎,赶紧引经据典,经过一番折腾之后,在https://groups.google.com/forum/#!topic/golang-nuts/O4RTszIyL7c最终找到了答案:

我们不需要手动地给go提供动态链接库,甚至于go根本不认识我们自己手动编译出的动态链接库。其实cgo提供了一种机制:它能够根据import”C”中引入的头文件,自动找到相应的源文件进行编译链接。这种机制的调用,需要用到go build命令。

输出结果如下:
在这里插入图片描述
佛曰:众生皆幻象,众生皆平等!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值