Files
notes/resource/go/待总结/CGO.md
T
2026-03-01 01:43:46 +08:00

3.7 KiB
Raw Blame History

title, created, source, tags
title created source tags
修复Go时区设置 2025-08-02 Cherry Studio

CGO(通常写作 cgo)是 Go 语言提供的一个工具和机制,允许 Go 程序调用 C 语言的函数、使用 C 的数据类型、链接 C 的库。它是 Go 与 C 之间互操作的桥梁。


🧱 为什么需要 CGO

Go 是一门现代系统编程语言,但它不能(也不打算)完全替代 C 在底层系统中的地位。许多操作系统 API、硬件驱动、已有库(如 OpenSSL、FFmpeg、SQLite)都是用 C 写的。

所以 Go 提供了 cgo,让开发者可以在 Go 代码中直接调用这些 C 接口。


🔧 如何使用 CGO?简单例子

package main

/*
#include <stdio.h>
*/
import "C"  // 这是关键:必须导入 "C" 这个伪包

func main() {
    C.puts(C.CString("Hello from C!"))
}

解释:

  • /* … */ 中的 C 代码会被 cgo 编译处理。
  • import "C" 不是导入真实包,而是 启用 cgo 模式,并提供访问 C 的符号(函数、变量等)。
  • C.puts:调用 C 标准库的 puts 函数。
  • C.CString("…"):将 Go 字符串转为 C 风格的 char*(需要手动释放,在复杂场景下要注意内存管理)。

🧩 CGO 能做什么?

功能 示例
调用 C 函数 C.printf(…), C.open(), C.sqrt()
使用 C 类型 C.int, C.struct_stat, C.size_t
定义 C 代码 在 Go 文件的注释中写 C 函数或头文件包含
链接外部 C 库 通过 #cgo LDFLAGS: -lxxx 链接 libcurl、libusb 等
传递数据 Go 和 C 之间传递整数、字符串、结构体指针等(需注意内存模型)

⚠️ 使用 CGO 的代价

虽然强大,但 cgo 有缺点:

缺点 说明
🐢 性能开销 跨 Go/C 边界有额外开销(栈切换、参数转换)
🔗 破坏静态编译 使用 cgo 后,编译出的程序依赖系统的 C 库(如 glibc),可能无法跨平台或静态链接
🧨 安全风险 C 没有内存安全,容易引入缓冲区溢出、空指针等 bug,可能导致整个 Go 程序崩溃
📦 构建复杂 需要 C 编译器(gcc/clang)环境,交叉编译更麻烦

因此,Go 社区常说:“cgo should be avoided unless absolutely necessary.


💡 实际应用场景

  1. 操作系统底层调用

    • 如你看到的例子:读取本地时区(调用 localtime_r
    • 获取网络接口信息、设置 socket 选项等
  2. 移动端开发(Android/iOS

    • Android:调用 JNI 或 Bionic C 库
    • iOS:调用系统框架(通过 C 封装)
  3. 集成已有 C/C++ 库

    • 比如图像处理用 OpenCV(通过 cgo 封装)
    • 数据库如 SQLitegithub.com/mattn/go-sqlite3 就用了 cgo
  4. 高性能计算或硬件交互

    • GPU、加密芯片、嵌入式设备驱动等

小结:什么是 CGO

CGO(cgo)是 Go 语言的一个功能,允许你在 Go 程序中调用 C 代码,实现与 C 的互操作。

  • 用途:访问系统底层 API、复用 C 库
  • 缺点:影响性能、可移植性和安全性
  • 📌 原则:能不用就不用;必须用时,尽量封装成干净接口

📚 官方文档参考


所以你在代码里看到的:

/*
#include <time.h>
*/
import "C"

这就是在启用了 cgo,接着调用 C 的 time()localtime_r() 函数 —— 这正是利用 C 的运行时能力来修复 Go 自身在某些平台上时区检测不准确的问题。