重新打包C类型导致在Go中出现类型转换错误

3

我正在尝试重新打包一些与现有C库集成的Go代码。

以下内容完美地运行。

文件1:

package avcodec

type Codec C.struct_AVCodec

文件2:
package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>
import "C" 
import (    
"unsafe" 
) 

type Codec C.struct_AVCodec

func (s *FormatContext) AvFormatGetVideoCodec() *Codec {    
  result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))
  return (*Codec)(result) // <- This works. Codec is defined in this package.
}

如果我试图将来自文件2的Codec引用或移动到一个单独的包中(例如文件1),我会收到以下错误信息: 无法将(func literal)((*C.struct_AVFormatContext)(s)) (type *C.struct_AVCodec)转换为类型*Codec 例如,以下操作将失败:
package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>
import "C" 
import (    
"avcodec"
"unsafe" 
) 

func (s *FormatContext) AvFormatGetVideoCodec() *avcodec.Codec {    
 result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))      
 return (*avcodec.Codec)(result) // <- This fails. Codec defined in avcodec.
}

这也失败了:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>    
import "C" 
import ( 
"avcodec"   
"unsafe" 
) 

type Codec avcodec.Codec

func (s *FormatContext) AvFormatGetVideoCodec() *Codec {    
  result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))
  return (*Codec)(result) // <- This also fails. Codec is based on avcodec.Codec.
}

我希望能够:

  1. 了解为什么它失败了,以及
  2. 确定如何更改打包方式,使函数使用在avcodec包中定义的Codec类型。

提前感谢。


那一行代码里面有很多东西。我建议逐个尝试每个部分,看看哪一个失败了。 - RayfenWindspear
错误发生在返回上。我简化了代码以突出强制转换错误。其他一切正常 :) - haroldcampbell
@JimB 看起来那个重新定义只是一个实验。 - RayfenWindspear
1
即使进行类型重新定义,我仍无法复制此故障。我们需要的是一个 [mcve]。 - JimB
1
@haroldcampbell:我现在想我明白你的意图了。是的,在一个包中定义的 C.struct_AVCodec 和在另一个包中定义的 C.struct_AVCodec 是不同的类型,因此它们之间的转换是不起作用的。如果你想要能够在其他包中从 avcodec.Codec 转换它,你需要使用 unsafe,或者直接在整个程序中使用 C 类型。C 类型系统不是 Go 类型系统,手动转换通常是必要的。 - JimB
显示剩余5条评论
1个回答

1
这个问题是由于Go语言表示类型的方式导致的。
例如,给定以下代码:
//Ex1
package avformat 
//.. deleted for simplicity

type Codec C.struct_AVCodec

"...and"。
//Ex2
package avcode 
//.. deleted for simplicity

type Codec C.struct_AVCodec

在上面的代码中,ex1中的C.struct_AVCodec与ex2中的不同,尽管它们在词法上相同。具体来说,ex1中的完全限定类型是avformat._Ctype_struct_AVCodec,而ex2中是avcodec._Ctype_struct_AVCodec。这就解释了为什么package avformat中的函数试图将任何外部类型(在本例中来自package avcodec)转换为本地的C.struct_AVCodec时会失败。

解决方案

为使其工作,需要依赖于类型断言。
package avformat

func (s *FormatContext) AvformatNewStream(c avcodec.ICodec) *Stream {
  v, _ := c.(*C.struct_AVCodec)
  return (*Stream)(C.avformat_new_stream((*C.struct_AVFormatContext)(s), (*C.struct_AVCodec)(v)))
}

"...and"。
package avcodec

type ICodec interface{}

1
关于 cgo 内部工作原理的出色回答。我一定会记住这个陷阱。 - RayfenWindspear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接