目录
- 总述
- 用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
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38package 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
将输出结果只存存到文件中。得到的结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 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
。
以下为示例代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86package 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) } }
编译运行结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28{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复杂结构体内容请搜索靠谱客的其他文章。
发表评论 取消回复