重新打包C类型会导致Go中的类型转换错误

时间:2017-04-03 19:27:01

标签: go casting package cgo

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

以下作品完美无缺。

文件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 引用或移动到单独的包中(例如文件1 ),我会收到错误:

无法转换(func literal)((* C.struct_AVFormatContext)(s))(类型* 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. 确定如何更改包装,以便该函数使用Codec包中定义的avcodec类型。
  3. 提前致谢。

1 个答案:

答案 0 :(得分:1)

由于Go代表了类型,因此失败了。

例如,给定:

//Ex1
package avformat 
//.. deleted for simplicity

type Codec C.struct_AVCodec

...和

//Ex2
package avcode 
//.. deleted for simplicity

type Codec C.struct_AVCodec

在上面的代码中,ex1中的C.struct_AVCodec与ex2中的C.struct_AVCodec不同,即使它们在词法上是相同的。

具体来说,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)))
}

...和

package avcodec

type ICodec interface{}