swig 之 go 语言调用c,多参数返回

这篇博客介绍了如何利用Swig在Go语言中调用C代码,特别是处理多参数数组返回的情况。作者指出,Swig能够自动处理Go和C之间的类型转换,并给出了将`int*`参数替换为`[]int32`的示例。通过修改接口文件和配置,成功实现了Go调用C函数并接收修改后的数组值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于任务的原因,有一个项目需要用go语言调用c代码。之前有接触过swig,因此直接上官网去swig,果不其然,它是支持go语言的,二话不说,直接搞起。

首先,如果您不熟悉swig,可以自行百度。然后,本人也是不熟悉go语言,只为了能在go语言顺利调用c代码,因此才考虑用swig。不过,我也有几个考虑的,第一,我有java调用c代码的经验(jni),我知道调用c代码,最关键的内存的回收要处理好,不然会有不可忽略的bug等着你,hhh;第二,我囫囵吞枣的看了下go的语法,大概了知道了go与c类型的转换,还有go语言指针、数组等区别,一时间也无法很好的写出比较优良的代码,于是把希望寄托于swig。

好了下面开始正题。

Swing and Go 官方文档很清楚交了你怎么使用swig 来封装你的c代码,让go顺利的调用它。

文档第一个列子就是

% swig -go -cgo -intgosize 32 example.i

需要注意的文档要求把代码文件放入 GOPATH/src。这个为了让你后面 import的时候直接加入包名而方便的,你可以不需要这么做。直接在自己希望的目录中,运行上面的代码。

首先,目录有的文件为:example.c example.i。直接运行

% swig -go -cgo -intgosize 32 example.i

然后,你会得到 example.go example_wrap.c。其中example_wrap.c 是对example.c的再一次封装,为了更好的让go语言调用c代码,做了很多go与c类型的处理。然后,example.go就是直接让其他go语言调用的函数接口,即当main.go 调用example.go的函数时,example.go 会调用 example_wrap.c,然后example_wrap.c会调用example.c。

可能我写的不太清楚,如果您希望有更清楚的,可以去找更详细的资料,或者直接看官网的资料。


这里有一个特殊的情况


/* File : example.c */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void test_a(int *p, int *q, int M, int m, int N,int n){

      for (int i = 0; i < m; i++) {
        printf("p[i] %d\n", p[i] + M);
          p[i]=11;
      }

      for (int i = 0; i < n; i++) {
        printf("q[i] %d\n", q[i] + N);
          q[i]=12;
      }
}

我希望能在go中调用该c函数,传入两个int数组p 和 q 并返回该数组的修改值。

在看了swig的官网的介绍之后,查到了官网的例子Swing and Go example,然后通过查找资料修改example.i,成功调用。

/* File : example.i */
%module example

%{
extern void test_a(int *p, int *q, int M, int m, int N,int n);
%}


%typemap(gotype) int *p ,int *q  "[]int32"

%typemap(in) (int *p),(int *q)
%{
    $1 = (int*)$input.array;
%}



extern  void test_a(int *p, int *q, int M, int m, int N,int n);

下面为大家介绍一下思路:

%typemap(gotype) int *p , int *q "[]int32"

该语义为,将 int* p 和 int *q 的c代码函数中的参数的类型替换为go的[]int32;


func Test_a (arg1 []int32, arg2 []int32, arg3 int, arg4 int, arg5 int, arg6 int) {
	_swig_i_0 := arg1
	_swig_i_1 := arg2
	_swig_i_2 := arg3
	_swig_i_3 := arg4
	_swig_i_4 := arg5
	_swig_i_5 := arg6
.....

可以看到,在example.go中 test_a的函数中的参数类型,已经得到了替换,也是我们希望的类型。

接下来

%typemap(in) (int *p),(int *q)
%{
    $1 = (int*)$input.array;
%}

该语义是告诉example_wrap.c,在go的数组和c的数组之间要做的处理。

我们知道,在swig会定义一个结构体

typedef struct { void* array; intgo len; intgo cap; } _goslice_;

用于转换go的数组与c的数组。

因此,我们真正的数组指针是array,len是数组长度,因此我们需要获得它。最终swig生成的代码如下


void _wrap_test_a_example_a6e85fed6d990a5b(_goslice_ _swig_go_0, _goslice_ _swig_go_1, intgo _swig_go_2, intgo _swig_go_3, intgo _swig_go_4, intgo _swig_go_5) {
  int *arg1 = (int *) 0 ;
  int *arg2 = (int *) 0 ;
  int arg3 ;
  int arg4 ;
  int arg5 ;
  int arg6 ;


  arg1 = (int*)_swig_go_0.array;


  arg2 = (int*)_swig_go_1.array;

  arg3 = (int)_swig_go_2;
  arg4 = (int)_swig_go_3;
  arg5 = (int)_swig_go_4; 
  arg6 = (int)_swig_go_5;

  test_a(arg1,arg2,arg3,arg4,arg5,arg6);

}

swing 其实很强大,还有很多未知等待大家去探索。

下面给出,剩下的例子

├── example
│   ├── example.c
│   ├── example.go
│   ├── example.i
│   └── example_wrap.c
├── testmain.go
package main

import (
    "fmt"
    "./example"
)

func main() {

    fmt.Println("Hello World!")

    ps := []int32{0, 0, 0, 0,0, 0,0, 0}
    qs := []int32{0, 0, 0, 0,0, 0,0, 0}

    example.Test_a(ps,qs,ctx,100, 8, 1000, 8)

    fmt.Println(ps)
    fmt.Println(qs)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值