本文总阅读量 本站访客数人次 本站总访问量
gongluck's blog
C/C++ Golang 音视频流媒体
CGO入门

C/C++加上GO代表什么?

代表着既可以使用GO快速的开发项目,同时可以接纳C/C++的庞大历史遗产和极高性能!而且在GO中使用C/C++十分简单!

代码仓库

https://github.com/gongluck/CGO-DEMO.git

准备

使用CGO,需要先安装gcc或者mingw。

启用CGO特性

package main

import "C"

func main() {
    println("hello, cgo")
}

就是这么简单,一句 import “C” 就是告诉 go build 命令在编译和链接阶段启动gcc编译器。

使用C标准库的函数

package main

//#include <stdio.h>
import "C"

func main() {
    C.puts(C.CString("hello, cgo"))
}

import “C” 上面紧接着的注释就是C代码,上面就是将标准库的头文件包含进我们的代码中。在GO中使用C的代码都是在伪包"C"中,所以使用C标准库中的 puts 函数就是 C.puts(…) 。由于C和GO中的字符(串)类型不是等价的,使用 C.CString(…) 将GO中的 string 转换成C的 char* 。

使用自定义C函数

package main

/*
#include <stdio.h>

static void SayHello(const char* s)
{
    puts(s);
}
*/
import "C"

func main() {
    C.SayHello(C.CString("hello, cgo\n"))
}

和前面使用C标准库的函数的例子差不多,只是将自定义函数的定义放到 import “C” 上面的注释中,接下来就可以在GO中通过"C"包使用了。另外,也可以将自定义C函数的定义放到C源码文件中,GO代码只在 import “C” 上面添加该函数的声明。

package main

//void SayHello(const char* s);
import "C"

func main() {
    C.SayHello(C.CString("hello, cgo\n"))
}

C源码文件的内容

#include <stdio.h>

void SayHello(const char* s)
{
    puts(s);
}

如果两个源码文件都放在同一层目录下,可以直接使用 go build 编译。

其实,自定义的C函数也可以用C++实现

#include <iostream>

extern "C" {
    #include "hello.h"
}

void SayHello(const char* s) {
    std::cout << s;
}

但是现在就必须通过一个C头文件给GO声明该函数

void SayHello(const char* s);

GO代码改为

package main

//#include "hello.h"
import "C"

func main() {
    C.SayHello(C.CString("hello, cgo\n"))
} 

函数的声明是C的,但是具体内部实现可以是C++的。而且能和GO结合使用的只能是C。

GO导出C接口

前面的例子都是GO调用C源码(接口),下面使用GO导出C接口。 首先在C头文件中声明函数,为了适配GO,注释了 const 修饰。

void SayHelloGo(/*const*/ char* s);

在GO源码中实现该接口

package main

import "C"

import "fmt"

//export SayHelloGo
func SayHelloGo(s *C.char) {
    fmt.Print(C.GoString(s))
}

通过CGO的 //export SayHello 指令将Go语言实现的函数导出为C语言函数。接下来就可以使用该实际是GO实现的C接口了

package main

//#include <hello.h>
import "C"

func main() {
    C.SayHelloGo(C.CString("hello, cgo Go\n"))
}

面向C接口的GO

package main

//void SayHello(_GoString_ s);
import "C"

import (
    "fmt"
)

func main() {
    C.SayHello("hello, cgo go")
}

//export SayHello
func SayHello(s string) {
    fmt.Print(s)
}

从Go1.10开始CGO新增加了一个_GoString_预定义的C语言类型,用来表示Go语言字符串。 上面一个GO源码文件中,发生了这样的调用过程。GO的main函数中,调用了"C"包中的 SayHello 这个C函数,实际这个 SayHello C函数是GO实现的,所以转向调用GO中的 SayHello


Last modified on 2020-04-09