记录下go和c互访注意事项

编译命令

go编译成dll:

go build -buildmode=c-shared -o dll文件名.dll go文件名.go

注意:编译成功后会在本地目录.生成一个dll和相应的.h头文件,其中描述的是go的数据类型在c中的对应.调用时建议引用.

简化版的加载dll:

gcc -s -w xxx.c xxx.dll -o xxx

-s -w压缩选项,可不要(顺便提一句,go编译的时候加入-ldflags="-s -w"可以减小体积).

实验背景

手头有个项目要完成c的中文处理,需要用到中文字符切片,但是c没有明确给出方法,而且文件编码很头疼.联想到golang不需要在意文件编码这一优势,所以需要互访.

实验1:通过调研go的函数来屏幕输出

实现细节

上手dll函数:

package main

import "fmt"
import "C"

//export Printf
func Printf(format, str string) {
    fmt.Printf(format, str)
}

func main(){}

要导出的函数前面一行必须一个空格不加一个不少的格式,写上:
//export 函数名
然后函数主体部分,都是正常的.然后必须有个main函数,不会被导出,但是编译器需要它,这是必须的,尤其是"package main"导致了必须存在main()函数
然后运行编译命令,生成:

下面写c语言调用代码:

#include "eee.h"
#include <stdio.h>

int main() {
	char fstr[]="哈哈哈中文输出,数据来源:c文件[%s]\n";
	GoString fm = {fstr, sizeof(fstr)};
    char *v = malloc(33);
    FILE *fp = fopen("a.txt", "r");
    if (!fp) {return;}
    fread(v, sizeof(char), 30, fp);
    GoString values={v,30};
    Printf(fm, values);
}

编译运行

结论

golang可以直接访问c的内存,毕竟a.txt的内容是保存在用c语言开辟的空间里.

实验2:go返回非指针类型给c

go:

//export Cut
func Cut(s string, i int) string{
	s1 := string([]rune(s)[i])
	print("in go1", s1)
	print("int go2", i)
	return s1
}


输出到关键一部分就不行了…

结论

(勉强挤出)go不要直接返回非指针结果,这回导致不可预料结果.解决方案[理论上]取结构体地址,把地址返回给c

实验3:go返回指针

返回*C.char试试呢?

//export Cut
func Cut(s string, i int) *C.char{
	s1 := string([]rune(s)[i])
	print("in go1", s1)
	print("int go2", i)
	return C.CString(s1)
}
    char *vvs = Cut(values, 1);
    GoString vv={vvs, strlen(vvs)+1};
    Printf(fm, vv);

结论

[反证法]直接返回指针是没问题的,c也可以直接访问.
[题外话]我又加了一句printf("%s\n"),也没问题

综上所述

c->go传参只要按照go提供的数据格式,就基本没问题;
go->c安全的话应该返回指针而不是数据内容.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dtsroy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值