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

huangapple go评论81阅读模式
英文:

Repackaging C types causes type cast error in Go

问题

我正在尝试重新打包一些与现有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) // <- 这个是有效的。Codec在这个包中被定义。
}

如果我尝试将文件2中的Codec引用或移动到一个单独的包中(例如文件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) // <- 这个会失败。Codec在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) // <- 这个也会失败。Codec基于avcodec.Codec。
}

我想要:

  1. 理解为什么会失败,
  2. 找出如何更改打包方式,以便函数使用在avcodec包中定义的Codec类型。

提前感谢。

英文:

I'm trying to repackage some go code that integrates with an existing C library.

The following works perfectly.

File 1:

package avcodec

type Codec C.struct_AVCodec

File 2:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include &lt;libavformat/avformat.h&gt;
//#include &lt;libavcodec/avcodec.h&gt;
import &quot;C&quot; 
import ( 	
&quot;unsafe&quot; 
) 

type Codec C.struct_AVCodec

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

If I try to reference or move Codec from File 2 into a separate package (eg. File 1) I get the error:

**cannot convert (func literal)((*C.struct_AVFormatContext)(s)) (type C.struct_AVCodec) to type Codec

For example, this fails:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include &lt;libavformat/avformat.h&gt;
//#include &lt;libavcodec/avcodec.h&gt;
import &quot;C&quot; 
import ( 	
&quot;avcodec&quot;
&quot;unsafe&quot; 
) 

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

This also fails:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include &lt;libavformat/avformat.h&gt;
//#include &lt;libavcodec/avcodec.h&gt;    
import &quot;C&quot; 
import ( 
&quot;avcodec&quot;	
&quot;unsafe&quot; 
) 

type Codec avcodec.Codec

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

I'd like to:

  1. Understand why it fails, and
  2. Identify how I can change the packaging so that the function uses the Codec type that is defined in the avcodec package.

Thanks in advance.

答案1

得分: 1

这是由于Go语言对类型的表示方式导致的问题。

例如,给定以下代码:

//Ex1
package avformat 
//.. 简化的代码已删除

type Codec C.struct_AVCodec

...和

//Ex2
package avcode 
//.. 简化的代码已删除

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{}
英文:

This was failing due to how Go represents types.

For instance, given:

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

type Codec C.struct_AVCodec

...and

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

type Codec C.struct_AVCodec

In the code above, the C.struct_AVCodec in ex1 is different from the C.struct_AVCodec in ex2, even though the same are lexically the same.

Specifically, the fully qualified type in ex1 is avformat._Ctype_struct_AVCodec, while ex2 is avcodec._Ctype_struct_AVCodec

This explains why the functions in the package avformat that were trying to cast anything from an external type (in this case from package avcodec) to the local C.struct_AVCodec were failing.

Solution

To get this to work, I relied on type assertions.

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{}

huangapple
  • 本文由 发表于 2017年4月4日 03:27:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/43192754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定