cgo 内存释放_CGO编程入门

本文详细介绍了Go语言中的CGO编程,包括快速入门、基础概念和内存管理。通过实例展示了如何从最简单的CGO程序开始,逐步引入C标准库函数、自定义C函数、C代码模块化以及面向C接口的Go编程。文章强调了CGO在内存释放方面的注意事项,如未释放可能导致内存泄漏,但在小型示例中通常由操作系统自动回收。此外,还探讨了如何使用Go语言重新实现C函数,以及CGO在模块化和跨语言接口设计上的灵活性。
摘要由CSDN通过智能技术生成

ace84acbcf247d125a4356ebac261b44.png

过去的经验往往是走向未来的枷锁,因为在过时技术中投入的沉没成本会阻碍人们拥抱新技术。

——
chai2010

曾经一度因未能习得C++令人眼花缭乱的新标准而痛苦不已;Go语言“少即是多”的大道至简的理念让我重拾信心,寻回了久违的编程乐趣。

——Ending

C/C++经过几十年的发展,已经积累了庞大的软件资产,它们很多久经考验而且性能已经足够优化。Go语言必须能够站在C/C++这个巨人的肩膀之上,有了海量的C/C++软件资产兜底之后,我们才可以放心愉快地用Go语言编程。C语言作为一个通用语言,很多库会选择提供一个C兼容的API,然后用其他不同的编程语言实现。Go语言通过自带的一个叫CGO的工具来支持C语言函数调用,同时我们可以用Go语言导出C动态库接口给其他语言使用。

本章主要讨论CGO编程中涉及的一些问题。

2.1 快速入门

本节将通过一系列由浅入深的小例子来快速掌握CGO的基本用法。

2.1.1 最简CGO程序

真实的CGO程序一般都比较复杂,不过我们可以由浅入深。一个最简CGO程序该是什么样的呢?要构造一个最简CGO程序,首先要忽视一些复杂的CGO特性,同时要展示CGO程序和纯Go程序的差别来。下面是我们构建的最简CGO程序:

  1. package main
  2. import "C"
  3. func main() {
  4. println("hello cgo")
  5. }

代码通过import "C"语句启用CGO特性,主函数只是通过Go内置的println()函数输出字符串,其中没有任何和CGO相关的代码。虽然没有调用CGO的相关函数,但是go build命令会在编译和链接阶段启动gcc编译器,这已经是一个完整的CGO程序了。

2.1.2 基于C标准库函数输出字符串

前面那个CGO程序还不够简单,现在来看看更简单的版本:

  1. package main
  2. //#include <stdio.h>
  3. import "C"
  4. func main() {
  5. C.puts(C.CString("Hello, Worldn"))
  6. }

这个版本不仅通过import "C"语句启用CGO特性,还包含C语言的<stdio.h>头文件。然后通过cgo包的C.CString()函数将Go语言字符串转换为C语言字符串,最后调用cgo包的C.puts()函数向标准输出窗口打印转换后的C字符串。

与1.2节中的CGO程序的最大不同是:我们改用C.Cstring来创建C语言字符串,而且改用puts()函数直接向标准输出打印,之前是采用fputs向标准输出打印。

没有释放使用C.CString创建的C语言字符串会导致内存泄漏。但是对这个小程序来说,这样是没有问题的,因为程序退出后操作系统会自动回收程序的所有资源。

2.1.3 使用自己的C函数

前面使用了标准库中已有的函数。现在我们先自定义一个叫作SayHello的C函数来实现打印,然后从Go语言环境中调用这个SayHello()函数:

  1. package main
  2. /*
  3. #include <stdio.h>
  4. static void SayHello(const char* s) {
  5. puts(s);
  6. }
  7. */
  8. import "C"
  9. func main() {
  10. C.SayHello(C.CString("Hello, Worldn"))
  11. }

SayHello()函数是我们自己实现的之外,其他部分和前面的例子基本相似。

我们也可以将SayHello()函数放到当前目录下的一个C语言源文件中(扩展名必须是.c)。因为是编写在独立的C文件中,为了允许外部引用,所以需要去掉函数的static修饰符。

  1. // hello.c
  2. #include <stdio.h>
  3. void SayHello(const char* s) {
  4. puts(s);
  5. }

然后在CGO部分先声明SayHello()函数,其他部分不变:

  1. package main
  2. //void SayHello(const char* s);
  3. import "C"
  4. func main() {
  5. C.SayHello(C.CString("Hello, Worldn"))
  6. }

既然SayHello()函数已经放到独立的C文件中了,我们自然可以将对应的C文件编译打包为静态库或动态库文件供使用。如果是以静态库或动态库方式引用SayHello()函数,需要将对应的C源文件移出当前目录࿰

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值