Golang cgo:如何在Go代码中调用C语言代码?

简介: Golang cgo:如何在Go代码中调用C语言代码?

如何在Go代码中调用C语言代码?

Go语言是通过自带的一个叫CGO的工具来支持C语言函数调用,同时我们可以用Go语言导出C动态库接口给其它语言使用。

方式一、直接在 Go 代码中写入 C 代码

检查是否开启cgo工具

首先,要查看是否已经开启cgo工具:go env | findstr CGO。若是0则为关闭状态,需要手动开启:set CGO_ENABLED=1
在这里插入图片描述

编写main.go文件

随后,新建一个 main.go 文件,在注释中写入 C 语言的代码,并且需要导入 Go 提供的 C 包 import "C"。Go 语言在看到导入这个包之后就知道如何去识别和处理注释中的 C 语言代码了,具体示例如下:

$\color{red}{注意C 代码和import "c"​​ 语句之间不能有空行 !}$

package main

// #include <stdio.h>
// #include <stdlib.h>
/*
    void print_fun(char *s) {
        printf("print used by C language: %s\n", s);
    }
*/
import "C"

func main() {
    cStr := C.CString("hello world !") // golang 操作c 标准库中的CString函数
    C.print_fun(cStr)                  // 调用C函数:print_fun 打印输出
}

在这里插入图片描述
这种方式的 C 代码和 Go 代码在同一个文件中,所以大家能明显发现这种方式的代码耦合度太高,仅适用于项目简单单一的情形。

一个更合理的方式应该是 C 代码单独在一个文件。


方式二、Go 直接调用 C 文件

那么,如果已经写好一个封装好的 C 文件代码,Go 语言该如何调用呢?

此时我们需要直接写好 C 相关代码,因为 Go 代码是无法对 C 代码文件进行重写或者修改的。

以如下文件目录结构,创建相关 .h.c.go文件:
在这里插入图片描述

C语言 .h 头文件
  • 编写 ​​hello.h​​ 头文件,示例代码如下:
#ifndef HELLO_H
#define HELLO_H

void print_fun1(char *s);

#endif
C语言 .c 源文件

编写 ​​hello.c​​ 源文件,示例代码如下:

#include "hello.h"
#include <stdio.h>

void print_fun1(char *s) {
    printf("print used by C language: %s\n", s);
}
Go语言 .go 文件

最后编写 ​​main.go​​ 文件:

  • 我们需要在 CFLAGS 参数中填入我们的 GOPath 路径, ​​#cgo CFLAGS: -I xxx​​,xxx这里也可以填写 绝对路径/相对路径
  • 然后在 LDFLAGS 中填入我们的 C 编译后的本地链接文件: ​​#cgo LDFLAGS: xxx/hello.a​​,xxx这里也可以填写 绝对路径/相对路径

$\color{red}{注意C 代码和import "c"​​ 语句之间不能有空行 !}$

具体示例如下:

package main

/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: ./hello.a
#include <stdlib.h>
#include <hello.h>
*/
import "C"

import (
    "unsafe"
)

func main() {
    cStr := C.CString("hello world !") // golang 操作c 标准库中的CString函数
    C.print_fun1(cStr)                 // 调用C函数:print_fun 打印输出

    defer C.free(unsafe.Pointer(cStr)) // 因为 CSstring 这个函数没有对变量申请的空间进行内存释放
}

在这里插入图片描述

编写完以上文件后,距离可运行的程序只有一步之遥了。

编译 c 代码
$ gcc -c *.c           # 生成.o文件

$ ar rs hello.a *.o # 生成.a文件
ar: creating archive hello.a

$ rm ./hello.o         # 删除已不需要的.o文件,linux下为rm命令,windows下为del命令

生成.a文件需要用到 ar 命令建立或修改备存文件,可参考:Linux ar命令

执行 go 代码
go run main.go

补充

使用了 cStr := C.CString("hello world !"),记得调用C.free(unsafe.Pointer(cStr))释放当前变量申请的内存空间。

可参考:golang 操作c 标准库中的CString函数注意事项

目录
相关文章
|
29天前
|
存储 安全 数据管理
C语言之考勤模拟系统平台(千行代码)
C语言之考勤模拟系统平台(千行代码)
49 4
|
17天前
|
JavaScript 前端开发 测试技术
在 golang 中执行 javascript 代码的方案详解
本文介绍了在 Golang 中执行 JavaScript 代码的四种方法:使用 `otto` 和 `goja` 嵌入式 JavaScript 引擎、通过 `os/exec` 调用 Node.js 外部进程以及使用 WebView 嵌入浏览器。每种方法都有其适用场景,如嵌入简单脚本、运行复杂 Node.js 脚本或在桌面应用中显示 Web 内容。
51 15
在 golang 中执行 javascript 代码的方案详解
|
18天前
|
运维 监控 Cloud Native
一行代码都不改,Golang 应用链路指标日志全知道
本文将通过阿里云开源的 Golang Agent,帮助用户实现“一行代码都不改”就能获取到应用产生的各种观测数据,同时提升运维团队和研发团队的幸福感。
|
19天前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
24天前
|
JSON Go 开发者
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。
36 4
|
26天前
|
存储 安全 物联网
C语言物联网开发之设备安全与代码可靠性隐患
物联网设备的C语言代码安全与可靠性至关重要。一是防范代码安全漏洞,包括缓冲区溢出和代码注入风险,通过使用安全函数和严格输入验证来预防。二是提高代码跨平台兼容性,利用`stdint.h`定义统一的数据类型,并通过硬件接口抽象与适配减少平台间的差异,确保程序稳定运行。
|
20天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
49 1
|
1月前
|
存储 Cloud Native Shell
go库介绍:Golang中的Viper库
Viper 是 Golang 中的一个强大配置管理库,支持环境变量、命令行参数、远程配置等多种配置来源。本文详细介绍了 Viper 的核心特点、应用场景及使用方法,并通过示例展示了其强大功能。无论是简单的 CLI 工具还是复杂的分布式系统,Viper 都能提供优雅的配置管理方案。
|
1月前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
1月前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
37 2