最近工作中需要使用部门中的c遗产,所以研究了一下cgo使用。体会就是,真香。
总结心得如下:
C.calloc
或者C.malloc
分配内存。两者的区别是calloc会填0初始化。calloc
,则在c中free
;在go调用的C.calloc
,使用goC.free
。这样就不容易出问题。**_Ctype_struct_FileInfo
转换成 []*_Ctype_struct_FileInfo
,int32不要转成int64。air *C.struct_Result
,而不是其它需要转换的类型。示例:分配c结构体指针,并使用c函数初始化它。
/*
#include "shm.h"
*/
import "C"
import (
"log"
"unsafe"
)
func main(){
var reporter *C.report_agent_shm_t = (*C.report_agent_shm_t)(
C.calloc(1, C.sizeof_report_agent_shm_t)) // report_agent_shm_t 定义在shm.h中, 注意 sizeof_report_agent_shm_t,无须使用unsafe.SizeOf
defer C.free(unsafe.Pointer(reporter)) // 在go中C.calloc,则在go中C.free
var ret C.int = C.shm_open(reporter) // 此时调用c代码中的函数初始化这个对象,shm_open定义在shm.h中
if ret < 0 {
log.Fatalf("open nfc shm failed:%v", ret)
}
// report已完成初始化,使用 reporter.read_index 可直接取用字段
}
示例:在go中创建一段内存,并调用C函数读取数组到内存,最终在go中使用数组
n := C.ulong(C.DEFAULT_BUCKET_CAPACITY * reporter.one_flow_size)
buf := C.malloc(n)
defer C.free(buf) // 在go中malloc,则在go中free
for{
C.memset(buf, 0, n)
ret := C.shm_dequeue(reporter, buf) // 调用c函数将内存填充为数组数据,ret是数组实际长度
if ret == 0 {
time.Sleep(time.Millisecond * 10)
continue
}
flowTuples := unsafe.Slice((*C.dc_flow_log_info_t)(buf), ret) // 将buf转为go的slice,第二个参数为slice的长度,类型为 []C.dc_flow_log_info_t
// 或者,将buf转换为go数组,类型为 *[DEFAULT_BUCKET_CAPACITY]_Ctype_struct_flow_log_info,这里要注意实际的长度ret可能小于DEFAULT_BUCKET_CAPACITY
// flowTuples := (*[C.DEFAULT_BUCKET_CAPACITY]C.dc_flow_log_info_t)(buf)
for i, item := range flowTuples {
log.Printf("total:%v buf %v %v\n", ret, i, item.pkts)
}
// ...
}
示例:创建结构体,并且包装free函数
来自:https://www.reddit.com/r/golang/comments/iqy423/cgo_golang_free_allocated_memory_of_array_of_c/
package main
/*
#include "stdlib.h"
#include "stdint.h"
#include "stdio.h"
typedef struct FileInfo{
char *Name;
char *Path;
}FileInfo;
typedef struct Result{
FileInfo **files;
}Result;
*/
import "C"
import "unsafe"
func main() {
for {
var aiList []*C.struct_FileInfo
aif := (*C.struct_FileInfo)(C.malloc(C.sizeof_struct_FileInfo))
aif.Name = C.CString("abcd")
aif.Path = C.CString("/path")
aiList = append(aiList, aif)
air := (*C.struct_Result)(C.malloc(C.sizeof_struct_Result))
air.files = &aiList[0]
FreeMemory(air, len(aiList))
}
}
func FreeMemory(air *C.struct_Result, totalFiles int) {
files := (*[1 << 30]*C.struct_FileInfo)(unsafe.Pointer(air.files))[:totalFiles]
for _, item := range files {
C.free(unsafe.Pointer(item.Name))
C.free(unsafe.Pointer(item.Path))
C.free(unsafe.Pointer(item))
}
C.free(unsafe.Pointer(air))
}