首页 > 技术文章 > cgo类型转换

snyn 2022-05-10 15:09 原文

Cgo总结(一)

这篇文章的目的:
探究c的基本类型到go类型的转换怎样才能安全;下面是根据之间的转换做的测试
结论是:
坑真多,自己要小心点;运行速度还慢,能不用就尽量不用!
测试内容如下:

1、基本转换

C类型 调用方法 Go类型 字节数(byte) 数值范围
char C.char byte 1 -128~127
signed char C.schar int8 1 -128~127
unsigned char C.uchar uint8 1 0~255
short int C.short int16 2 -32768~32767
short unsigned int C.ushort uint16 2 0~65535
int C.int int 4 -2147483648~2147483647
unsigned int C.uint uint32 4 0~4294967295
long int C.long int32 or int64 4 -2147483648~2147483647
long unsigned int C.ulong uint32 or uint64 4 0~4294967295
long long int C.longlong int64 8 -9223372036854776001~9223372036854775999
long long unsigned int C.ulonglong uint64 8 0~18446744073709552000
float C.float float32 4 -3.4E-38~3.4E+38
double C.double float64 8 1.7E-308~1.7E+308
wchar_t C.wchar_t wchar_t 2 0~65535
void * unsafe.Pointer

1.1 char —>byte

package main
/*
#include<stdio.h>
char a = -128;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := byte(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果:
-128
类型为: main._Ctype_schar
128
类型为: uint8
代码2:
package main
/*
#include<stdio.h>
	 char  a = -127;
*/
import "C"
import (
	"fmt"
	"reflect"
)

func main() {
	b := int8(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果为:
-127
类型为: main._Ctype_char
-127
类型为: int8
由上面看出byte 跟uint8的功能一样,问题是为啥有byte的存在呢?

1.2 signed char—>int8

package main
/*
#include<stdio.h>
signed char a = 12;
*/
import "C"
import (
	"fmt"
	"reflect"
)

func main() {
	b := byte(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果:
12
类型为: main._Ctype_schar
12
类型为: uint8

1.3 unsigned char---->uint8

package main
/*
#include<stdio.h>
 unsigned char a = 254;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := byte(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果为:
254
类型为: main._Ctype_uchar
254
类型为: uint8

1.4 short int ----->int16

package main
/*
#include<stdio.h>
 short a = -32768;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := int16(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果:
-32768
类型为: main._Ctype_short
-32768
类型为: int16

1.5 short unsigned int ---->uint16

package main
/*
#include<stdio.h>
 short unsigned int  a = 65535;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := uint16(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果:
65535
类型为: main._Ctype_ushort
65535
类型为: uint16

1.6 int —> int

package main
/*
#include<stdio.h>
 int  a = -2147483648;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := int(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果为:
-2147483648
类型为: main._Ctype_int
-2147483648
类型为: int

1.7 unsigned int ----->uint32

package main
/*
#include<stdio.h>
 unsigned int  a = 4294967295;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := uint32(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果:
4294967295
类型为: main._Ctype_uint
4294967295
类型为: uint32

1.8 long int —>int32 or int64

package main
/*
#include<stdio.h>
 long int  a = 2147483647;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := uint32(C.a)
	c := uint64(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(c)
	fmt.Println("类型为:",reflect.TypeOf(c))
}
结果:
2147483647
类型为: main._Ctype_long
2147483647
类型为: uint32
2147483647
类型为: uint64

1.9 long unsigned int----->uint32 or uint64

package main
/*
#include<stdio.h>
 long unsigned int  a = 4294967295;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := uint32(C.a)
	c := uint64(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(c)
	fmt.Println("类型为:",reflect.TypeOf(c))
}

2.0 long long int ----->int64

package main
/*
#include<stdio.h>
 long long int  a = -9223372036854776001;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := int32(C.a)
	c := int64(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(c)
	fmt.Println("类型为:",reflect.TypeOf(c))
}
结果:
9223372036854775615
类型为: main._Ctype_longlong
-193
类型为: int32
9223372036854775615
类型为: int64

只有int64能接收到

2.1 long long unsigned int —> uint64

package main
/*
#include<stdio.h>
 long long unsigned int  a = -9223372036854776001;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := uint32(C.a)
	c := uint64(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(c)
	fmt.Println("类型为:",reflect.TypeOf(c))
}
结果为:
9223372036854775615
类型为: main._Ctype_ulonglong
4294967103
类型为: uint32
9223372036854775615
类型为: uint64

只有uint64能接收到

2.2 float---->float32

package main
/*
#include<stdio.h>
 float  a = -3.14;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := float32(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
}
结果为:
类型为: main._Ctype_float
-3.14
类型为: float32

2.3 double—>float64

package main
/*
#include<stdio.h>
 double  a = -3.14159267333333333333333;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	b := float32(C.a)
	c := float64(C.a)
	fmt.Println(C.a)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(c)
	fmt.Println("类型为:",reflect.TypeOf(c))
}
结果为:
-3.1415926733333333
类型为: main._Ctype_double
-3.1415927
类型为: float32
-3.1415926733333333
类型为: float64

2.5 void * ---->*

package main
/*
#include<stdio.h>
 int  *a = 65535;
 void *p =&a;
 void printpoint(){
 printf("point:%p\n",p);
 }
*/
import "C"
import (
"fmt"
"reflect"
"unsafe"
)

func main() {
	b := unsafe.Pointer(C.p)
	fmt.Println(C.p)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println(b)
	fmt.Println("类型为:",reflect.TypeOf(b))
	fmt.Println(C.printpoint())
}
结果:
0x53ec28
类型为: *main._Ctype_int
0x53ec28
类型为: unsafe.Pointer
[]
point:000000000053EC28

由以上看出从c到go的指针还是一样

总结:

在使用过程中转数据经常会造成数据不准的情况,查的时候特别费精力, 在 C 中的整形比如 int 在标准中是没有定义具体字长的,但一般默认是 4 字节,对应 CGO 类型中 C.int 则明确定义了字长是 4 ,但 golang 中的 int 字长则是 8 ,因此对应的 golang 类型不是 int 而是 int32 。为了避免go在调用C的时候还要考虑复杂的类型,建议使用 C99 标准的数值类型,对应的转换关系如下:

C语言类型 CGO类型 Go语言类型
int8_t C.int8_t int8
uint8_t C.uint8_t uint8
int16_t C.int16_t int16
uint16_t C.uint16_t uint16
int32_t C.int32_t int32
uint32_t C.uint32_t uint32
int64_t C.int64_t int64
uint64_t C.uint64_t uint64

使用代码:

package main
/*
#include <stdint.h>
 int8_t a = -128;
 uint8_t b= 255;
 int16_t c= -32768;
 uint16_t d= 65535;
 int32_t e = -2147483648;
 uint32_t f = 4294967295;
 int64_t g = -922337203685477601;
 uint64_t h = 922337203685477599;
*/
import "C"
import (
"fmt"
"reflect"
)

func main() {
	fmt.Println("---------------int8-------------")
	a1 := int8(C.a)
	fmt.Println(C.a)
	fmt.Println(a1)
	fmt.Println("类型为:",reflect.TypeOf(C.a))
	fmt.Println("转后的类型:",reflect.TypeOf(a1))
	fmt.Println("---------------uint8-------------")
	b1 := uint8(C.b)
	fmt.Println(C.b)
	fmt.Println(b1)
	fmt.Println("类型为:",reflect.TypeOf(C.b))
	fmt.Println("转后的类型:",reflect.TypeOf(b1))

	fmt.Println("---------------int16-------------")
	c1 := int16(C.c)
	fmt.Println(C.c)
	fmt.Println(c1)
	fmt.Println("类型为:",reflect.TypeOf(C.c))
	fmt.Println("转后的类型:",reflect.TypeOf(c1))
	fmt.Println("---------------uint16-------------")
	d1 := uint16(C.d)
	fmt.Println(C.d)
	fmt.Println(d1)
	fmt.Println("类型为:",reflect.TypeOf(C.d))
	fmt.Println("转后的类型:",reflect.TypeOf(d1))

	fmt.Println("---------------int32-------------")
	e1 := int32(C.e)
	fmt.Println(C.e)
	fmt.Println(e1)
	fmt.Println("类型为:",reflect.TypeOf(C.e))
	fmt.Println("转后的类型:",reflect.TypeOf(e1))
	fmt.Println("---------------uint32-------------")
	f1 := uint32(C.f)
	fmt.Println(C.f)
	fmt.Println(f1)
	fmt.Println("类型为:",reflect.TypeOf(C.f))
	fmt.Println("转后的类型:",reflect.TypeOf(f1))

	fmt.Println("---------------int64-------------")
	g1 := int64(C.g)
	fmt.Println(C.g)
	fmt.Println(g1)
	fmt.Println("类型为:",reflect.TypeOf(C.g))
	fmt.Println("转后的类型:",reflect.TypeOf(g1))
	fmt.Println("---------------uint64-------------")
	h1 := uint64(C.h)
	fmt.Println(C.h)
	fmt.Println(h1)
	fmt.Println("类型为:",reflect.TypeOf(C.h))
	fmt.Println("转后的类型:",reflect.TypeOf(h1))
}

推荐阅读