go与c互相调用

简介: 此例子来自于go源码中,借此来和大家分享一下两者如何调用,网上很多文章语言不详,也没有一个完整的测试例子 目录结构 首先src 目录下有 testcgowin目录下: 这里的_obj目录是cgo生成的 这里需要展示的是go中如何调用c语言导出函数,以及在c语言中如何调用go的导出函数.

此例子来自于go源码中,借此来和大家分享一下两者如何调用,网上很多文章语言不详,也没有一个完整的测试例子

  1. 目录结构

首先src 目录下有

testcgowin目录下:

这里的_obj目录是cgo生成的

这里需要展示的是go中如何调用c语言导出函数,以及在c语言中如何调用go的导出函数.

关键是cthread.go和cthread_windows.c两个文件

  1. go文件

cthread.go内容:

package ctestcgowin


// extern void doAdd(int, int);
import "C"

import (
"sync"
"fmt"
)

var sum struct {
sync.Mutex
i int
}

//export Add
func Add(x int) {
defer func() {
recover()
}()
sum.Lock()
sum.i += x
sum.Unlock()
var p *int
*p = 2
}

func TestCthread() {
sum.i = 0
C.doAdd(10, 6)

want := 10 * (10 - 1) / 2 * 6
if sum.i != want {
fmt.Printf("sum=%d, want %d\n", sum.i, want)
}
fmt.Println("want=",want)
}

这里的:

// extern void doAdd(int, int);
import "C"

这两行非常关键,必须紧挨着,不能有空行,而且要紧跟着package语句,import要单独写

这里的注释相当于c语言声明了一个函数,你用#include当然也可以。遵循的都是c的语法,少个分号都是会报错的。

然后是下面两行:

//export Add
func Add(x int) {

export Add表示这是go要导出的一个函数,这样c里面可以调用。

如果此行注释删掉,c文件将会提示找不到Add函数。

cthread_windows.c:18: undefined reference to `Add'

  1. c语言文件

// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include "_cgo_export.h"

__stdcall
static unsigned int
addThread(void *p)
{
int i, max;

max = *(int*)p;
for(i=0; i<max; i++)
Add(i);
return 0;
}

void
doAdd(int max, int nthread)
{
enum { MaxThread = 20 };
int i;
uintptr_t thread_id[MaxThread];

if(nthread > MaxThread)
nthread = MaxThread;
for(i=0; i<nthread; i++)
thread_id[i] = _beginthreadex(0, 0, addThread, &max, 0, 0);
for(i=0; i<nthread; i++) {
WaitForSingleObject((HANDLE)thread_id[i], INFINITE);
CloseHandle((HANDLE)thread_id[i]);
}
}

 

我不晓得这个宏WIN32_LEAN_AND_MEAN什么意思,跟着写就行了,也没有去查阅文档以及代码。

这里doAdd是导出函数,addThread不需要导出,所以加了static,

#include "_cgo_export.h"是因为我们需要调用go的导出函数Add,有兴趣的可以看看_obj目录

到此为止,相互之间的关系已经说明白了,当然go与c语言之间的类型转换,留作以后再说。

  1. 编译生成.a文件

接下来如果想要利用这个lib,很简单,

运行cgo生成必要的文件,然后go install将编译生成testcgowin.a文件,此文件在pkg\windows_386目录下

  1. 利用.a文件

直接看testcgowin.go文件内容即可:

package main
import "testcgowin"


func main(){
ctestcgowin.TestCthread();
}

 

  1. 结语

c和go互相调用的关键都是通过注释实现的,并且cgo会自己编译相应的.c文件,不需要特别说明,只需要放到相应目录下即可。

总的来说go为了和c互操作做了很多,虽然没法像c++那么方便,但是基本上来收还是很顺利的。

目录
相关文章
|
9天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
46 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
29天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
40 7
|
29天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
29天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
101 71
|
28天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
105 67
|
1月前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
101 62
|
4天前
|
算法 安全 Go
Go 语言中实现 RSA 加解密、签名验证算法
随着互联网的发展,安全需求日益增长。非对称加密算法RSA成为密码学中的重要代表。本文介绍如何使用Go语言和[forgoer/openssl](https://github.com/forgoer/openssl)库简化RSA加解密操作,包括秘钥生成、加解密及签名验证。该库还支持AES、DES等常用算法,安装简便,代码示例清晰易懂。
31 12
|
29天前
|
存储 Go
go语言中映射
go语言中映射
37 11