在Golang中使用C语言代码实例

cgo 使得在 Golang 中可以使用 C 代码。

Hello World

为了有一个较为直观的了解,我们来看一个简单的例子,创建文件 main.go:

代码如下:

package main
 
/*
#include <stdio.h>
 
void sayHi() {
    printf("Hi");
}
*/
import "C"
 
func main() {
    C.sayHi()
}

执行程序:

代码如下:

go run main.go

程序执行并输出 hi(更多的范例可以见 $GOROOT/misc/cgo)。

Windows 下的准备工作

如果想要在 Windows 上使用 cgo,那么需要安装 gcc 编译器,这里我使用 mingw-w64。

设置编译和链接标志

我们使用 import “C” 导入的是一个伪包(pseudo-package),我们通过其来使用 C 代码。在 import “C” 之前,紧跟着 import “C” 的注释可以包括:

1.编译器和链接器标志
2.C 代码

我们可以通过 #cgo 指令来设置编译器和链接器标志,例如:

代码如下:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"

附带提及一点的是,这些指令中可以包含构建约束(build constraint),详细内容见:http://golang.org/pkg/go/build/#hdr-Build_Constraints

常用的 #cgo 指令有:

1.CPPFLAGS、CFLAGS 指令被用于编译当前包中的 C 文件(任何的 .c、.s、.S 文件)
2.CPPFLAGS、CXXFLAGS 指令被用于编译当前包中的 C++ 文件(任何的 .cpp、.cc、.cxx 文件)
3.LDFLAGS 指令用于指定链接器标志
4.pkg-config 指令用于通过 pkg-config 工具获取编译器和链接器标志(例如:#cgo pkg-config: png cairo)

Golang 引用 C

结构体上需要注意的点:

1.C 结构体的域名称如果为 Golang 的关键字时,访问时需要在域名称前面加上 _。比如说,C 中有一个结构体变量 x,此变量对应的结构体中有一个域 type,那么在 Golang 中需要通过 x._type 来访问 type 域
2.结构体的位域、非对齐数据等无法在 Golang 中表示时会被忽略
3.Golang 结构体中不能使用 C 类型的域

标准的 C 数值类型对应:

1.C.char
2.C.schar(signed char)
3.C.uchar(unsigned char)
4.C.short
5.C.ushort(unsigned short)
6.C.int
7.C.uint(unsigned int)
8.C.long
9.C.ulong(unsigned long)
10.C.longlong(long long)
11.C.ulonglong(unsigned long long)
12.C.float
13.C.double

任何的 C 函数(包括 void 函数)都可以返回一个返回值和 C 的 errno 变量(作为错误):

代码如下:

n, err := C.sqrt(-1)
_, err := C.voidFunc()

直接调用 C 函数指针目前还无法支持。

有一些特殊的函数可以用于 C 类型和 Golang 类型之间转换(通过数据拷贝的方式),伪定义如下:

代码如下:

// Golang 的字符串转为 C 字符串
// C 的字符串是使用 malloc 分配的,因此,此函数的调用者
// 需要调用 C.free 来释放内存
func C.CString(string) *C.char
 
// 转换 C 字符串到 Golang 字符串
func C.GoString(*C.char) string
 
// 转换一定长度的 C 字符串到 Golang 字符串
func C.GoStringN(*C.char, C.int) string
 
// 转换一块 C 内存区域到 Golang 的字节数组中去
func C.GoBytes(unsafe.Pointer, C.int) []byte

其他需要注意的点:

1.C 语言中的 void* 对应 unsafe.Pointer
2.C 语言中的结构、联合、枚举类型(而非变量),在 Golang 中需要加上 struct_、union_、enum_ 前缀访问。由于 Golang 中没有联合这种数据类型,因此 C 的联合在 Golang 中被表示为字节数组
3.和 C 语言等价的那些类型是不可以导出的

(0)

相关推荐

  • golang使用正则表达式解析网页

    废话少说,直接奉上代码: 复制代码 代码如下: package main import ( "fmt" "time" "io/ioutil" "net/http" "regexp" "strings" ) func main() {     ip_pool := []string{                 "172.16.1.128",            

  • ubuntu下搭建Go语言(golang)环境

    Go语言是谷歌2009发布的第二款开源编程语言.Go语言专门针对 多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程. 还是我自己的电脑,我自己安装的是ubuntu 12.04版本的,直接介绍安装吧!其实搭建环境很简单! 复制代码 代码如下: sudo apt-get install python-setuptools python-dev build-essential //安装mercurial依赖 sudo easy_insta

  • Mac OS系统安装golang教程

    下载golang安装包 下载地址: http://www.golangtc.com/download https://code.google.com/p/go/downloads/list go1.4.darwin-amd64-osx10.8.pkg  go1.4 Mac OS X (x86 64-bit) PKG installer 设置环境变量 配置 GOROOT 和 GOPATH: 复制代码 代码如下: 创建目录下的go文件夹: mkdir ~/go 下面的东西放到.bash_rc(也可能

  • golang语言中for循环语句用法实例

    本文实例讲述了golang语言中for循环语句用法.分享给大家供大家参考.具体分析如下: for循环是用来遍历数组或数字的.用for循环遍历字符串时,也有 byte 和 rune 两种方式.第一种为byte,第二种rune. 复制代码 代码如下: package main import ( "fmt" ) func main() { s := "abc汉字" for i := 0; i < len(s); i++ { fmt.Printf("%c,&

  • 理解Golang中的数组(array)、切片(slice)和map

    我比较喜欢先给出代码,然后得出结论 数组 复制代码 代码如下: package main import (     "fmt" ) func main() {     arr := [...]int{1, 2, 3}     //打印初始的指针     fmt.Printf("the pointer is : %p \n", &arr)     printPointer(arr) } func printPointer(any interface{}) {

  • Golang极简入门教程(一):基本概念

    安装 Golang 在 http://golang.org/dl/ 可以下载到 Golang.安装文档:http://golang.org/doc/install. Hello Go 我们先创建一个文件 hello.go: 复制代码 代码如下: package main   import "fmt"   func main() {     fmt.Printf("hello Golang\n"); } 执行此程序: 复制代码 代码如下: go run hello.g

  • 利用Go语言实现简单Ping过程的方法

    一.准备工作 安装最新的Go 1.由于Google被墙的原因,如果没有VPN的话,就到这里下载:http://www.golangtc.com/download 2.使用任意文本编辑器,或者LiteIDE会比较方便编译和调试 二.编码 要用到的package: import ( "bytes" "container/list" "encoding/binary" "fmt" "net" "os&q

  • Golang极简入门教程(四):编写第一个项目

    workspace Golang 的代码必须放置在一个 workspace 中.一个 workspace 是一个目录,此目录中包含几个子目录: 1.src 目录.包含源文件,源文件被组织为包(一个目录一个包) 2.pkg 目录.包含包对象(package objects) 3.bin 目录.包含可执行的命令 包源文件(package source)被编译为包对象(package object),命令源文件(command source)被编译为可执行命令(command executable).

  • Golang实现的聊天程序服务端和客户端代码分享

    实现逻辑 1.Golang 版本  1.3 2.实现原理: 1.主进程建立TCP监听服务,并且初始化一个变量 talkChan := make(map[int]chan string) 2.当主进程ACCEPT连接请求后,利用go 启动一个协程A去维持和客户端的连接,把taokChan带入到协程里 3.和客户端建立连接的协程A,发送消息给客户端,使其发送自己的用户信息. 4.协程A在收到客户端发送的用户信息后,建立一个此用户对应的管道 talkChan[uid] = make(chan stri

  • Golang极简入门教程(三):并发支持

    Golang 运行时(runtime)管理了一种轻量级线程,被叫做 goroutine.创建数十万级的 goroutine 是没有问题的.范例: 复制代码 代码如下: package main   import (     "fmt"     "time" )   func say(s string) {     for i := 0; i < 5; i++ {         time.Sleep(100 * time.Millisecond)       

随机推荐