在Go语言中调用C代码的技巧

在 Go 语言中调用 C 代码的技巧

虽然 Go 语言旨在提升编程体验,减少 C 语言的复杂性,但 C 语言依然是非常强大的编程语言,并且在很多情况下依然十分有用。比如在使用数据库或设备驱动程序时,它们可能是用 C 语言编写的。这意味着在某些情况下,你可能需要在 Go 项目中调用 C 代码。

在同一个文件中调用 C 代码

最简单的调用 C 代码的方式是将 C 代码直接包含在 Go 源文件中。虽然这需要一些特殊处理,但这种方式速度很快,也不算太复杂。不过,如果你在同一个项目中多次使用这种功能,可能需要重新考虑这种方式是否合适,或者是否应该换一种编程语言。

下面展示了一个包含 C 代码和 Go 代码的文件 cGo.go,它分为三部分:

package main

// #include <stdio.h>
// void callC() {
//     printf("调用 C 代码!\n");
// }
import "C"

import "fmt"

func main() {
    fmt.Println("这是 Go 语言中的一条语句!")
    C.callC()
    fmt.Println("这是另一条 Go 语言中的语句!")
}

在上面的代码中,callC() C 函数通过 C.callC() 调用。运行该代码会产生以下输出:

$ go run cGo.go
这是 Go 语言中的一条语句!
调用 C 代码!
这是另一条 Go 语言中的语句!
使用单独文件调用 C 代码

接下来讨论如何在 C 代码位于单独的文件时,从 Go 程序中调用它。假设我们有两个已经编写好的 C 函数,不想在 Go 中重写它们。

C 代码

首先,C 代码包含在两个文件中:callC.hcallC.c

callC.h 文件内容如下:

#ifndef CALLC_H
#define CALLC_H
void cHello();
void printMessage(char* message);
#endif

callC.c 文件内容如下:

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

void cHello() {
    printf("来自 C 语言的问候!\n");
}

void printMessage(char* message) {
    printf("Go 语言发送的消息是: %s\n", message);
}

这两个文件存储在 callClib 目录下。当然,你也可以使用任何其他目录名称。

Go 代码

接下来是 Go 源代码,它被命名为 callC.go,分为三部分展示:

package main

// #cgo CFLAGS: -I${SRCDIR}/callClib
// #cgo LDFLAGS: ${SRCDIR}/callC.a
// #include <stdlib.h>
// #include <callC.h>
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Println("即将调用 C 函数!")
    C.cHello()

    fmt.Println("即将调用另一个 C 函数!")
    myMessage := C.CString("这是来自 Mihalis 的消息!")
    defer C.free(unsafe.Pointer(myMessage))
    C.printMessage(myMessage)

    fmt.Println("调用完成!")
}

在 Go 中传递字符串给 C 函数时,需要使用 C.CString() 创建一个 C 字符串,同时要使用 defer 语句来确保不再需要时释放内存。

编译和执行混合的 Go 和 C 代码

当你编写好 C 代码和 Go 代码后,接下来就是编译并执行这些文件。幸运的是,所有关键信息都已经包含在 Go 文件中,唯一的重点是编译 C 代码以创建一个静态库。你可以执行以下命令来完成这些操作:

$ ls -l callClib/
total 16
-rw-r--r--@ 1 mtsouk  staff  162 Jan 10 09:17 callC.c
-rw-r--r--@ 1 mtsouk  staff   89 Jan 10 09:17 callC.h

$ gcc -c callClib/*.c

$ ls -l callC.o
-rw-r--r--  1 mtsouk  staff  952 Jan 22 22:03 callC.o

$ /usr/bin/ar rs callC.a *.o
ar: creating archive callC.a

$ ls -l callC.a
-rw-r--r--  1 mtsouk  staff  4024 Jan 22 22:03 callC.a

完成这些步骤后,callC.a 文件将位于与 callC.go 文件相同的目录中。此时你可以编译 Go 代码:

$ go build callC.go

$ ls -l callC
-rwxr-xr-x  1 mtsouk  staff  2403184 Jan 22 22:10 callC

执行生成的可执行文件:

$ ./callC
即将调用 C 函数!
来自 C 语言的问候!
即将调用另一个 C 函数!
Go 语言发送的消息是: 这是来自 Mihalis 的消息!
调用完成!
总结

如果你只需要调用少量的 C 代码,那么在同一个 Go 文件中同时包含 C 和 Go 代码是一个简洁的选择。然而,当涉及到更复杂的项目时,创建一个静态的 C 库可能是更好的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值