项目中需要用Golang调用C生成密码,因此借机熟悉了一下cgo的一些用法。
基本用法网上已经有教程,但是关于字符串的传递的文章还不多,因此记录下。
1. 编写C文件,包含一个函数,函数接受字符串,同时返回字符数组。注意这里的返回的数组是malloc申请的,调用的时候需要释放。
//foo.c
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#define LENGTH 16
char* foo(char *input) {
char* m = malloc(LENGTH*sizeof(char));
sprintf(m, "%s", input);
return m;
}
以下是相应头文件
//foo.h
#ifndef _FOO_H_
#define _FOO_H_
char* foo(char* input);
#endif
2. 编译成动态链接库
gcc -c -fpic foo.c
gcc -shared foo.o -o foo.so
3. golang调用C代码
package main
// #include <stdio.h>
// #include <stdlib.h>
// #include "foo.h"
import "C"
import (
"fmt"
"unsafe"
)
func main() {
cs := C.CString("hello")
result := C.foo(cs)
str := C.GoString(result)
C.free(unsafe.Pointer(cs))
C.free(unsafe.Pointer(result))
fmt.Println(str)
}
注意:
- 由于将动态链接文件和go代码放在同一目录下了,所以在golang中就不需要再通过cgo指定链接的路径和文件名了
- 传递参数的时候需要将golang中的string和c类型的char *作类型转换,转换方法通过C.CString来实现
- 调用C函数之后的返回值类型是C类型的char*, 需要通过C.GoString来作类型转换。此函数会将原来的内容拷贝一份,因此即使先free掉result,str变量的使用依然不受影响
- 一定记得调用C.free释放指针指向的内存,防止内存泄漏