【问题标题】:Passing a Go slice of float32 to CGo as a C float[]将 float32 的 Go 切片作为 C float[] 传递给 CGo
【发布时间】:2021-12-06 12:53:42
【问题描述】:

我正在尝试使用 catboost 来预测一组浮点数。

CalcModelPredictionSingle 的文档中,它以"floatFeatures - array of float features" 为参数: https://github.com/catboost/catboost/blob/master/catboost/libs/model_interface/c_api.h#L175

但是,当我尝试传递一个浮点数组时,我得到了这个错误:

Cannot use type []*_Ctype_float as *_Ctype_float in assignment.

表示它期待一个浮点数。我是不是用错了函数?

我正在使用 cgo,这是我的代码的一部分:

```
floats := []float32{}
//gets populated

floatsC := make([]*C.float, len(floats))
for i, v := range floats {
    floatsC[i] = (*C.float)(&v)
}

if !C.CalcModelPredictionSingle(
    model.Handle,
    ([]*C.float)(floatsC),
    ...
) {
    return
}

【问题讨论】:

  • 在 C 中,指向浮点数的指针与指向浮点数数组的第一个元素的指针(在传递给函数之后)无法区分,问题必须在进行中......跨度>
  • @GradyPlayer 事实上,事实上(作为一个参数)C 将“T 的数组 N”与“指向 T 的指针”混为一谈,而 Go 没有,这就是问题所在。正如 rustyx 回答的那样,诀窍是使用 Go 数组或切片并获取指向第一个元素的指针,这只是手动表达 C 编译器在调用者处所做的事情。

标签: c go catboost catboostregressor


【解决方案1】:

API 需要floats 的数组,但您尝试创建的[]*C.float 是指向floats 的指针数组。这些是不兼容的类型,这正是编译器所告诉的。

好消息是这些都不是必需的,因为 Go []float32 与 C float[] 布局兼容,因此您可以将 Go 切片作为指向其第一个元素的指针直接传递给 C 函数。

floats := []float32{}
//gets populated
    
if !C.CalcModelPredictionSingle(
    model.Handle,
    (*C.float)(&floats[0]), // pass the pointer to the first slice element
    C.size_t(len(floats)),  // pass the slice length
    ...
) {
    return
}

请注意,在 C 中 float[]*float 是同一个东西。

【讨论】:

  • 非常感谢您的回复。我对 Catboost 很陌生。你能向我解释为什么只传递第一个元素就足够了吗?数组的其余部分不是被忽略了吗?
  • @Gargameli 在 C 中,当你调用一个函数时,它不会传入任何东西的整个数组,而且 C 对数组的长度一无所知,它只表示为第一个元素的地址。当你将一个数组传递给一个函数时,它被称为“退化”为一个指针。
  • @GradyPlayer 非常感谢,你帮我省了很多麻烦。我被这些例子吓坏了。
猜你喜欢
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多