我是靠谱客的博主 标致台灯,最近开发中收集的这篇文章主要介绍CGO解析C复杂结构体的三种方法总述用C解析go生成兼容结构体直接C.struct_使用结语参考,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • 总述
  • 用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_使用结语参考所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部