前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >cgo笔记: 内存分配与对象转换

cgo笔记: 内存分配与对象转换

作者头像
超级大猪
发布2023-03-14 17:38:15
7070
发布2023-03-14 17:38:15
举报
文章被收录于专栏:大猪的笔记大猪的笔记

最近工作中需要使用部门中的c遗产,所以研究了一下cgo使用。体会就是,真香。

总结心得如下:

  1. 在go中,可以调用C.calloc或者C.malloc分配内存。两者的区别是calloc会填0初始化。
  2. 分配内存中要注意,在c调用的calloc,则在c中free;在go调用的C.calloc,使用goC.free。这样就不容易出问题。
  3. 更方便的做法是,仅使用c的结构和函数,其它操作都使用go完成。好处是,C的代码会非常的简单。
  4. 在强制类型转换时,一定要对应类型。比如pointer指向什么,就转成什么。**_Ctype_struct_FileInfo 转换成 []*_Ctype_struct_FileInfo,int32不要转成int64。
  5. helper函数签名保持简单,不要进行更多的类型转换。例如,Free函数传入c结构体air *C.struct_Result,而不是其它需要转换的类型。
  6. 不要跨包cgo,不支持。在包内闭环,外部public接口使用go的签名。

示例:分配c结构体指针,并使用c函数初始化它。

代码语言:javascript
复制
/*
#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中使用数组

代码语言:javascript
复制
    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/

代码语言:javascript
复制
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))
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-03-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档