c语言 long x=8.8,18-Go语言和C语言交叉访问

本文详细介绍了如何在Go语言中调用C语言函数,包括在Go源文件中直接编写C代码、使用cgo工具、转换数据类型以及处理字符串和指针。同时,也提及了C语言调用Go函数的可能性,尽管较少使用。文章还涵盖了枚举、结构体和数组类型的互操作,并提供了一个实例演示如何通过Go调用C函数实现无缓冲区输入。
摘要由CSDN通过智能技术生成

Go语言中调用C语言函数

在Go语言开篇中我们已经知道, Go语言与C语言之间有着千丝万缕的关系, 甚至被称之为21世纪的C语言

所以在Go与C语言互操作方面,Go更是提供了强大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中编写C代码,这是其他语言所无法望其项背的

格式:

在import "C"之前通过单行注释或者通过多行注释编写C语言代码

在import "C"之后编写Go语言代码

在Go语言代码中通过C.函数名称() 调用C语言代码即可

注意: import "C"和前面的注释之间不能出现空行或其它内容, 必须紧紧相连

package main

//#include

//void say(){

// printf("Hello World\n");

//}

import "C"

func main() {

C.say()

}

package main

/*

#include

void say(){

printf("Hello World\n");

}

*/

import "C"

func main() {

C.say()

}

Go语言中没有包名是C的包, 但是这个导入会促使Go编译器利用cgo工具预处理文件

在预处理过程中,cgo会产生一个临时包, 这个包里包含了所有C函数和类型对应的Go语言声明

最终使得cgo工具可以通过一种特殊的方式来调用import "C"之前的C语言代码

常规问题:

如果编译报错cc1.exe: sorry, unimplemented: 64-bit mode not compiled in

说明你使用的是64的golang,而你使用的32位的MinGW,所以需要下载64位的mingw并配置环境变量

C语言中调用Go语言函数(很少使用)

在Go代码中通过 //export Go函数名称导出Go的函数名称

在C代码中通过 extern 返回值类型 Go函数名称(形参列表); 声明Go中导出的函数名称

注意: //export Go函数名称和extern 返回值类型 Go函数名称(形参列表);不能在同一个文件中

package main

import "C"

import "fmt"

// 导出Go函数声明, 给C使用

//export GoFunction

func GoFunction() {

fmt.Println("GoFunction!!!")

}

package main

/*

#include

// 声明Go中的函数

extern void GoFunction();

void CFunction() {

printf("CFunction!\n");

GoFunction();

}

*/

import "C"

func main() {

C.CFunction()

}

由于不在同一个文件, 所以需要通过go build或者go install同时编译多个文件

Go中使用C语言的类型

基本数据类型

在Go中可以用如下方式访问C原生的数值类型:

C.char,

C.schar (signed char),

C.uchar (unsigned char),

C.short,

C.ushort (unsigned short),

C.int, C.uint (unsigned int),

C.long,

C.ulong (unsigned long),

C.longlong (long long),

C.ulonglong (unsigned long long),

C.float,

C.double

Go的数值类型与C中的数值类型不是一一对应的。因此在使用对方类型变量时必须显式转型操作

package main

/*

#include

int num = 123;

float value = 3.14;

char ch = 'N';

*/

import "C"

import "fmt"

func main() {

var num1 C.int = C.num

fmt.Println(num1)

var num2 int

//num2 = num1 // 报错

num2 = int(num1)

fmt.Println(num2)

var value1 C.float = C.value

fmt.Println(value1)

var value2 float32 = float32(C.value)

fmt.Println(value2)

var ch1 C.char = C.ch

fmt.Println(ch1)

var ch2 byte = byte(C.ch)

fmt.Println(ch2)

}

字符串类型

C语言中并不没有字符串类型,在C中用带结尾'\0'的字符数组来表示字符串;而在Go中string类型是原生类型,因此在两种语言互操作是必须要做字符串类型的转换

C字符串转换Go字符串: C.GoString(str)

Go字符串转换C字符串: C.CString(str)

package main

/*

#include

char *str = "www.it666.com";

void say(char *name){

printf("my name is %s", name);

}

*/

import "C"

import (

"fmt"

"unsafe"

)

func main() {

// 1.C语言字符串转换Go语言字符串

str1 := C.str

str2 := C.GoString(str1)

fmt.Println(str2)

// 2.Go语言字符串转换C语言字符串

str := "lnj"

cs := C.CString(str)

C.say(cs)

// 注意: 转换后所得到的C字符串cs并不能由Go的gc所管理,我们必须手动释放cs所占用的内存

C.free(unsafe.Pointer(cs))

}

指针类型

原生数值类型的指针类型可按Go语法在类型前面加上*,例如:var p *C.int。

而void*比较特殊,用Go中的unsafe.Pointer表示。

unsafe.Pointer:通用指针类型,用于转换不同类型的指针,不能进行指针运算

uintptr:用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收

也就是说 unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为uintptr 进行指针运算

package main

/*

#include

int num = 123;

void *ptr = #

*/

import "C"

import (

"fmt"

"unsafe"

)

func main() {

// 这是一个C语言变量

var num C.int = C.num

// 这是一个C语言指针

var p1 *C.int = &num

fmt.Println(*p1)

//var p2 *C.void = C.ptr // 报错

// 利用unsafe.Pointer接收viod *

var p2 unsafe.Pointer = C.ptr

// 将unsafe.Pointer转换为具体类型

var p3 *C.int = (*C.int)(p2)

fmt.Println(*p3)

}

枚举类型

C语言中的枚举类型在Go语言中的表现形式为C.enum_XXX

访问枚举和访问普通变量无异, 直接通过C.枚举值即可

package main

/*

#include

enum Gender {

GenderMale,

GenderFemale,

GenderYao

};

*/

import "C"

import "fmt"

func main() {

var sex C.enum_Gender = C.GenderMale

fmt.Println(sex)

sex = C.GenderFemale

fmt.Println(sex)

sex = C.GenderYao

fmt.Println(sex)

}

结构体类型

C语言中的结构体类型在Go语言中的表现形式为C.struct_XXX

访问结构体 直接通过结构体变量.属性名称即可

package main

/*

#include

struct Point {

float x;

float y;

};

*/

import "C"

import (

"fmt"

)

func main() {

// 1.利用C的结构体类型创建结构体

var cp C.struct_Point = C.struct_Point{6.6, 8.8}

fmt.Println(cp)

fmt.Printf("%T\n", cp)

// 2.将C语言结构体转换为Go语言结构体

type GoPoint struct {

x float32

y float32

}

var gp GoPoint

gp.x = float32(cp.x)

gp.y = float32(cp.y)

fmt.Println(gp)

}

数组类型

C语言中的数组与Go语言中的数组差异较大, C中的数组是指针类型, Go中的数组是值类型

目前似乎无法直接显式的在两者之间进行转型,官方文档也没有说明。

package main

/*

#include

int cArray[5] = {1, 2, 3, 4, 5};

*/

import "C"

import "fmt"

func main() {

var cArr [5]C.int = C.cArray

fmt.Println(cArr)

fmt.Printf("%T\n", cArr)

}

利用Go语言调用C语言函数, 实现无缓冲区输入

请在终端运行

package main

/*

#include

char lowerCase(char ch){

// 1.判断当前是否是小写字母

if(ch >= 'a' && ch <= 'z'){

return ch;

}

// 注意点: 不能直接编写else, 因为执行到else不一定是一个大写字母

else if(ch >= 'A' && ch <= 'Z'){

return ch + ('a' - 'A');

}

return ' ';

}

char getCh(){

// 1.接收用户输入的数据

char ch;

scanf("%c", &ch);

setbuf(stdin, NULL);

// 2.大小写转换

ch = lowerCase(ch);

// 3.返回转换好的字符

return ch;

}

*/

import "C"

import "fmt"

func main() {

for{

fmt.Println("请输入w a s d其中一个字符, 控制小人走出迷宫")

var ch byte = byte(C.getCh())

fmt.Printf("%c", ch)

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值