2.3.1 数值类型
在Go语言中访问C语言的符号时,一般是通过虚拟的“C”包访问,比如C.int
对应C语言的int
类型。有些C语言的类型是由多个关键字组成,但通过虚拟的“C”包访问C语言类型时名称部分不能有空格字符,比如unsigned int
不能直接通过C.unsigned int
访问。因此CGO为C语言的基础数值类型都提供了相应转换规则,比如C.uint
对应C语言的unsigned int
。
Go语言中数值类型和C语言数据类型基本上是相似的,以下是它们的对应关系表2-1所示。
C语言类型 | CGO类型 | Go语言类型 |
---|---|---|
char | C.char | byte |
singed char | C.schar | int8 |
unsigned char | C.uchar | uint8 |
short | C.short | int16 |
unsigned short | C.ushort | uint16 |
int | C.int | int32 |
unsigned int | C.uint | uint32 |
long | C.long | int32 |
unsigned long | C.ulong | uint32 |
long long int | C.longlong | int64 |
unsigned long long int | C.ulonglong | uint64 |
float | C.float | float32 |
double | C.double | float64 |
size_t | C.size_t | uint |
表 2-1 Go语言和C语言类型对比
需要注意的是,虽然在C语言中int
、short
等类型没有明确定义内存大小,但是在CGO中它们的内存大小是确定的。在CGO中,C语言的int
和long
类型都是对应4个字节的内存大小,size_t
类型可以当作Go语言uint
无符号整数类型对待。
CGO中,虽然C语言的int
固定为4字节的大小,但是Go语言自己的int
和uint
却在32位和64位系统下分别对应4个字节和8个字节大小。如果需要在C语言中访问Go语言的int
类型,可以通过GoInt
类型访问,GoInt
类型在CGO工具生成的_cgo_export.h
头文件中定义。其实在_cgo_export.h
头文件中,每个基本的Go数值类型都定义了对应的C语言类型,它们一般都是以单词Go为前缀。下面是64位环境下,_cgo_export.h
头文件生成的Go数值类型的定义,其中GoInt
和GoUint
类型分别对应GoInt64
和GoUint64
:
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef float GoFloat32;
typedef double GoFloat64;
除了GoInt
和GoUint
之外,我们并不推荐直接访问GoInt32
、GoInt64
等类型。更好的做法是通过C语言的C99标准引入的<stdint.h>
头文件。为了提高C语言的可移植性,在<stdint.h>
文件中,不但每个数值类型都提供了明确内存大小,而且和Go语言的类型命名更加一致。Go语言类型<stdint.h>
头文件类型对比如表2-2所示。
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 |
表 2-2 <stdint.h>
类型对比
前文说过,如果C语言的类型是由多个关键字组成,则无法通过虚拟的“C”包直接访问(比如C语言的unsigned short
不能直接通过C.unsigned short
访问)。但是,在<stdint.h>
中通过使用C语言的typedef
关键字将unsigned short
重新定义为uint16_t
这样一个单词的类型后,我们就可以通过C.uint16_t
访问原来的unsigned short
类型了。对于比较复杂的C语言类型,推荐使用typedef
关键字提供一个规则的类型命名,这样更利于在CGO中访问。
学员评价