搜索文档搜索当前语言
使用 C2Go
候选版本v0.20260809.0-rc.5

本文档对应当前协同发布候选版本。

使用 C2Go

GC 感知分配

在 Go heap 上分配带类型的 C 对象,并保留准确的指针布局。

gc_malloc 会在 Go heap 上分配清零内存。与普通 C 分配不同,它接收 runtime 类型信息,让垃圾回收器知道哪些机器字保存着指针。

分配一个 record

#include <c2go.h>
#include <stddef.h>
#include <stdint.h>

struct managed Node {
    struct Node *next;
    int value;
};

struct Node *new_node(int value) {
    struct Node *node = gc_malloc(
        c2go_typeinfo(struct Node),
        sizeof(struct Node)
    );
    if (node == NULL) {
        return NULL;
    }
    node->value = value;
    return node;
}

c2go_typeinfo(struct Node) 是通过宏公开的编译器 builtin,返回这个具名 managed record 对应的 Go runtime 类型描述符。无需手写或注册 pointer bitmap。

它没有对应的 free;对象不可达后由 Go GC 回收。

当数据必须活过当前 C 栈帧时,也应把它改写为 heap 分配。不要把 &local 存进这个对象;C2Go 不会自动把 local 移动到堆。详见栈指针逃逸安全。

分配数组

当每个元素都需要重复相同指针元数据时,使用 gc_malloc_array:

struct Node *nodes = gc_malloc_array(
    c2go_typeinfo(struct Node),
    sizeof(struct Node),
    count
);

runtime 会在整块内存中重复元素的 pointer bitmap,类似为 Go slice 分配 backing array。

当前 inline helper 直接计算 elem_size * count,不会替调用方检测乘法溢出。处理不可信长度时,先验证 count <= SIZE_MAX / elem_size,并检查返回值是否为 NULL。

分配不含指针的 blob

把 NULL 作为类型信息会得到 GC 不扫描指针的内存:

unsigned char *bytes = gc_malloc(NULL, byte_count);

只有确认其中永远不会保存 managed 指针时才能这样做。把 managed 指针隐藏在 blob 中,可能让被引用对象在 GC 看来已经不可达。

不要混用所有权模型

allocator 世界 释放方式
gc_malloc / gc_malloc_array typed managed Go heap 自动 GC
malloc / calloc / realloc c2go-libc unmanaged C 语义 storage free

不要对 typed Go heap 指针调用 free,也不要假设原生库可以无限期保存 managed 指针。如果原生 API 接管所有权,应使用该 API 明确要求的 allocator 并复制数据,或设计稳定 handle 边界;c2go-libc 的 malloc 并不等同于宿主系统 malloc。

类型信息限制

c2go_typeinfo 要求具名且完整的 record 类型。匿名 record 和保留的 runtime 标识符会被拒绝。Packed 或自定义 alignment 的 managed record 会产生 warning,生成布局也与 target 相关;可移植的公开类型应优先使用自然布局。

下一章把相同规则扩展到多文件项目与 LTO。