为了账号安全,请及时绑定邮箱和手机立即绑定

转到 / Cgo - 如何访问 C 结构的字段?

转到 / Cgo - 如何访问 C 结构的字段?

Go
慕盖茨4494581 2022-09-19 20:54:29
我在Go中开发了一个应用程序,用于将音频文件从一种格式转码为另一种格式:我使用使用 Cgo 绑定 FFmpeg C 库的 goav 库:https://github.com/giorgisio/goav/戈夫图书馆; 具有一个类型定义,该定义将原始 FFmpeg 库 C-结构 AV输出格式转换为:package avformattype (    OutputFormat               C.struct_AVOutputFormat)在我的代码中,我有一个名为 的变量,该变量的类型是.outputFOutputFormatC.struct_AVOutputFormat真正的结构有以下字段:CAVOutputFormatname, long_name, mime_type, extensions, audio_codec, video_codec, subtitle_codec,..以及许多领域。请参见: https://ffmpeg.org/doxygen/2.6/structAVOutputFormat.html我通过以下方式验证了情况并到达:fmt.Println(outputF){0x7ffff7f23383 0x7ffff7f23907 0x7ffff7f13c33 0x7ffff7f23383 86017 61 0 128 <nil> 0x7ffff7f8cfa0 <nil> 3344 0x7ffff7e3ec10 0x7ffff7e3f410 0x7ffff7e3ecc0 <nil> 0x7ffff7e3dfc0 <nil> <nil> <nil> <nil> <nil> <nil> 0 0x7ffff7e3e070 0x7ffff7e3e020 <nil>}音频编解码器字段位于位置,包含586017我使用包验证了字段名称:reflectval := reflect.Indirect(reflect.ValueOf(outputF))fmt.Println(val)fmt.Println("Fieldname: ", val.Type().Field(4).Name)Output:Fieldname:  audio_codec我尝试使用以下命令访问原始字段:audio_codecAVOutputFormatfmt.Println(outputF.audio_codec)ERROR: outputF.audio_codec undefined (cannot refer to unexported field or method audio_codec)fmt.Println(outputF._audio_codec)ERROR: outputF._audio_codec undefined (type *avformat.OutputFormat has no field or method _audio_codec)正如我在Cgo文档中读到的:在Go文件中,可以通过在下划线前缀来访问作为Go中关键字的C结构字段名称:如果x指向带有名为“type”的字段的C结构,x._type访问该字段。无法在 Go 结构中表示的 C 结构字段(如位字段或未对齐的数据)在 Go 结构中被省略,替换为适当的填充以到达下一个字段或结构的末尾。但我不知道我做错了什么。编辑:好吧,肯定不需要下划线,因为audio_codec不是Go中的关键字。我现在明白了。但是仍然存在一个问题,为什么我无法访问CStruct字段“audio_codec”。
查看完整描述

1 回答

?
慕哥6287543

TA贡献1831条经验 获得超10个赞

GO / CGO有一些特质,你在这里碰到:

type OutputFormat C.struct_AVOutputFormat是 go 类型声明,而不是别名。将其视为薄包装而不是别名可能会有所帮助。因此,C.struct_AVOutputFormat字段不会导出,这就是您获得OutputFormat != C.struct_AVOutputFormatERROR: outputF.audio_codec undefined (cannot refer to unexported field or method audio_codec)

如果该字段被调用Audio_codec它将符合go对导出标识符的定义,我们可以访问它,但事实并非如此。

有一种方法可以解决这个问题,但我建议在继续之前三思而后行,因为它使用不安全的指针,并且您的程序可能会在运行时失去可移植性和/或稳定性。如果您想了解更多信息,这是不安全指针的良好介绍

现在,如果您确实确定要执行此操作,解决方案是将指针转换为不安全的指针,然后将其转换为指向 的指针。请注意,这需要您加载 FFMPEG 标头才能获得OutputFormatC.struct_AVOutputFormatC.struct_AVOutputFormat

//#cgo pkg-config: libavformat

//#include <libavformat/avformat.h>

import "C"

import (

    "fmt"

    "unsafe"

    "github.com/giorgisio/goav/avformat"

)


func getOutput() *avformat.OutputFormat {

  // calls out to avformat and gets an OutputFormat back

}


func main() {

    outputF := getOutput()

    coutput := *(*C.struct_AVOutputFormat)(unsafe.Pointer(outputF))


    fmt.Println(coutput.audio_codec) // This should now work

}

警告:我还没有测试cgo包配置和导入是否正确,但这适用于一个简单的C库,我站起来尝试一下。<libavformat/avformat.h>


查看完整回答
反对 回复 2022-09-19
  • 1 回答
  • 0 关注
  • 81 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信