概述
目录
- 总述
- 用C解析
- go生成兼容结构体
- 直接`C.struct_`使用
- 结语
- 参考
总述
初学go,项目用到的库基本都是C/C++实现,需要大量写CGO。这两天遇到一些C定义的复杂结构体,所以准备梳理,个人总结如下。
- C里解析结构体,然后输出。可以参考下面链接的文章。
- go里定义兼容的结构体,然后使用。
- 类似第二条,但是不提前定义,使用C.struct_xxx的方法“硬写”
用C解析
请参考下文给出的用C做解析文章。
个人觉得既然都写go了,能用go实现的不想再去写C。不过,直觉认为某些情况下,使用C来解析时最稳妥的。可以在C里写个接口专门解析复杂结构体,直接输出json也不错。
go生成兼容结构体
一种方法是手写,容易出错还枯燥。另一种方法是使用CGO工具中的 -godefs
功能自动生成结构体声明。但是生成结果可能有偏差。
godefs
的参数要求是go文件。下面示例将C定义的结构体放在了序言中,也可以放在头文件中再引用。
文件名定为朴实无华的main.go
。
package main
/*
#define MAX_CLASSIFICATION_NUM 5
struct iRF_Classification
{
int candidate_num;
int index[MAX_CLASSIFICATION_NUM];
float confidence[MAX_CLASSIFICATION_NUM];
};
typedef struct iRF_Bound_Tag
{
float score;
struct iRF_Classification classification;
int x_left_top;
int y_left_top;
int x_right_top;
int y_right_top;
int x_left_bottom;
int y_left_bottom;
} iRF_Bound;
#define MAX_OBJECT_NUM 3
typedef struct iRF_Object_Tag
{
int num;
iRF_Bound bound[MAX_OBJECT_NUM];
} iRF_Object;
*/
import "C"
type IRF_Classification C.struct_iRF_Classification
type IRF_Bound C.iRF_Bound
type IRF_Object C.iRF_Object
const Sizeof_IRF_Classification = C.sizeof_struct_iRF_Classification
const Sizeof_IRF_Bound = C.sizeof_iRF_Bound
const Sizeof_IRF_Object = C.sizeof_iRF_Object
请注意示例中iRF_Classification
结构体,专门没有用typedef
与另外两个做区分。其在go中调用时,需要加上C.struct_
前缀。
此时执行go tool cgo -godefs main.go
,或者go tool cgo -godefs main.go > new_main.go
将输出结果只存存到文件中。得到的结果如下:
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs main.go
package main
type IRF_Classification struct {
Num int32
Index [5]int32
Confidence [5]float32
}
type IRF_Bound struct {
Score float32
Classification IRF_Classification
X_left_top int32
Y_left_top int32
X_right_top int32
Y_right_top int32
X_left_bottom int32
Y_left_bottom int32
}
type IRF_Object struct {
Num int32
Bound [3]IRF_Bound
}
const Sizeof_IRF_Classification = 0x2c
const Sizeof_IRF_Bound = 0x48
const Sizeof_IRF_Object = 0xdc
Sizeof_IRF_Classification
等得到的C类型结构体的长度,之后可以通过unsafe.Sizeof()
获取go类型结构体长度后进行比较。
直接C.struct_
使用
如果C中的结构体通过typedef
定义名称,在go中调用时直接使用C.xxx
,否则,需要C.struct_xxx
。
以下为示例代码。
package main
/*
#define MAX_CLASSIFICATION_NUM 5
struct iRF_Classification
{
int candidate_num;
int index[MAX_CLASSIFICATION_NUM];
float confidence[MAX_CLASSIFICATION_NUM];
};
typedef struct iRF_Bound_Tag
{
float score;
struct iRF_Classification classification;
int x_left_top;
int y_left_top;
int x_right_top;
int y_right_top;
int x_right_bottom;
int y_right_bottom;
int x_left_bottom;
int y_left_bottom;
} iRF_Bound;
#define MAX_OBJECT_NUM 3
typedef struct iRF_Object_Tag
{
int num;
iRF_Bound bound[MAX_OBJECT_NUM];
} iRF_Object;
*/
import "C"
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
var irfObject C.iRF_Object
irfObject = C.iRF_Object{
num: 100,
bound: [3]C.iRF_Bound{
{
score: 0.8,
x_left_top: 1,
y_left_top: 2,
x_right_top: 3,
y_right_top: 4,
x_right_bottom: 5,
y_right_bottom: 6,
x_left_bottom: 7,
y_left_bottom: 8,
classification: C.struct_iRF_Classification{
candidate_num: 3,
index: [5]C.int{10,20,30,40,50},
confidence: [5]C.float{100,0,200,1,300,2},
},
},
},
}
fmt.Printf("%+vn",irfObject)
fmt.Println(irfObject.num)
fmt.Println(irfObject.bound[0].score)
fmt.Println(irfObject.bound[0].classification.candidate_num)
fmt.Println(irfObject.bound[0].classification.index[3])
fmt.Println(len(irfObject.bound[0].classification.index))
fmt.Println(len(irfObject.bound[0].classification.confidence))
fmt.Println(unsafe.Sizeof(irfObject.bound[0].classification))
fmt.Println(C.sizeof_struct_iRF_Classification)
fmt.Println(C.sizeof_iRF_Object)
typeOfiRF_Object := reflect.TypeOf(irfObject)
for i := 0 ; i < typeOfiRF_Object.NumField();i++ {
fmt.Println(typeOfiRF_Object.Field(i).Type)
}
typeOfiRF_Bound := reflect.TypeOf(irfObject.bound[0])
for i := 0 ; i < typeOfiRF_Bound.NumField();i++ {
fmt.Println(typeOfiRF_Bound.Field(i).Type)
}
typeOfiRF_Classification := reflect.TypeOf(irfObject.bound[0].classification)
for i := 0 ; i < typeOfiRF_Classification.NumField();i++ {
fmt.Println(typeOfiRF_Classification.Field(i).Type)
}
}
编译运行结果如下:
{num:100 bound:[{score:0.8 classification:{candidate_num:3 index:[10 20 30 40 50] confidence:[100 200.1 300.2 0 0]} x_left_top:1 y_left_top:2 x_right_top:3 y_right_top:4 x_right_bottom:5 y_right_bottom:6 x_left_bottom:7 y_left_botto
m:8} {score:0 classification:{candidate_num:0 index:[0 0 0 0 0] confidence:[0 0 0 0 0]} x_left_top:0 y_left_top:0 x_right_top:0 y_right_top:0 x_right_bottom:0 y_right_bottom:0 x_left_bottom:0 y_left_bottom:0} {score:0 classification
:{candidate_num:0 index:[0 0 0 0 0] confidence:[0 0 0 0 0]} x_left_top:0 y_left_top:0 x_right_top:0 y_right_top:0 x_right_bottom:0 y_right_bottom:0 x_left_bottom:0 y_left_bottom:0}]}
100
0.8
3
40
5
5
44
44
244
main._Ctype_int
[3]main._Ctype_struct_iRF_Bound_Tag
main._Ctype_float
main._Ctype_struct_iRF_Classification
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
main._Ctype_int
[5]main._Ctype_int
[5]main._Ctype_float
结语
新学go语言,用的方法可能比较笨拙,希望大佬指正。
参考
go生成兼容结构体
用C做解析
官方CGO文档
官方示例
最后
以上就是标致台灯为你收集整理的CGO解析C复杂结构体的三种方法总述用C解析go生成兼容结构体直接C.struct_使用结语参考的全部内容,希望文章能够帮你解决CGO解析C复杂结构体的三种方法总述用C解析go生成兼容结构体直接C.struct_使用结语参考所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复