【问题标题】:ccall with Array type in signature calling a struct in C from Julia签名中带有数组类型的 ccall 从 Julia 调用 C 中的结构
【发布时间】:2015-09-16 17:24:03
【问题描述】:

我无法从 Julia 调用 C 函数。这可能是一个普遍有用的问题,但我将在我正在努力解决的具体环境中描述它。我正在尝试创建一个bson 对象:

BSONObject("{a:1}")

所以这个对象的构造函数被调用:

BSONObject(jsonString::String) = begin
    jsonCStr = bytestring(jsonString)
    bsonError = BSONError()
    _wrap_ = ccall(
        (:bson_new_from_json, libbson),
        Ptr{Void}, (Ptr{Uint8}, Csize_t, Ptr{Uint8}),
        jsonCStr,
        length(jsonCStr),
        bsonError._wrap_
        )
    _wrap_ != C_NULL || error(bsonError)
    bsonObject = new(_wrap_, None)
    finalizer(bsonObject, destroy)
    return bsonObject
end

https://github.com/pzion/LibBSON.jl/blob/master/src/BSONObject.jlLibBSON 包中需要处理MongoDB 查询,但设置不是特别重要。重要的是ccall,它传递一个字符串jsonCStr、这个字符串的长度和bsonError._wrap_。最后一个对象来自https://github.com/pzion/LibBSON.jl/blob/master/src/BSONError.jl,是一个数组:

type BSONError
    _wrap_::Vector{Uint8}

    function BSONError()
        return new(Array(Uint8, 512))
    end
end

BSONError对象的上述构造函数中创建了一个512个Uint8的数组。这个 Julia bsonError._wrap_ 在 C 中引用了以下 struct

typedef struct
{
   uint32_t domain;
   uint32_t code;
   char     message[504];
} bson_error_t;

参见http://api.mongodb.org/libbson/current/bson_error_t.html,这个结构的长度是 4 + 4 + 504 = 512,所以看起来没问题。

现在回到ccall,它的类型签名是Ok:Ptr{Uint8}指向字符串,Csize_t是它的大小类型,Ptr{Uint8}指向struct。但是,后者返回错误消息:

LoadError: MethodError: `convert` has no method matching convert(::Type{Ptr{UInt8}}, ::Array{UInt8,1})
This may have arisen from a call to the constructor Ptr{UInt8}(...),
since type constructors fall back to convert methods.
Closest candidates are:
  call{T}(::Type{T}, ::Any)
  convert{T<:Union{Int8,UInt8}}(::Type{Ptr{T<:Union{Int8,UInt8}}}, !Matched::Cstring)
  convert{T}(::Type{Ptr{T}}, !Matched::UInt64)
  ...
while loading In[2], in expression starting on line 1

 in convert at /Users/szalmaf/.julia/v0.4/LibBSON/src/BSONError.jl:21
 in call at /Users/szalmaf/.julia/v0.4/LibBSON/src/BSONObject.jl:33

显然,试图将Array 转换为Ptr{UInt8} 类型。

Julia 手册 http://julia.readthedocs.org/en/latest/manual/calling-c-and-fortran-code/#mapping-c-types-to-julia 在“将 C 类型映射到 Julia”部分的“位类型”小节中说 Julia Array{T,N} 应该作为 Ptr{T} 传递,在这种情况下 TUInt8 .所以 Julia ccall 看起来不错,但仍然有该错误消息。这是一个非常紧迫的问题,因为它阻止了数据库中更复杂的查询。关于如何解决这个ccall 问题的任何建议?

附:请注意,如果您安装了 LibBSON 包和 libbson C 库附带的 Mongo 包。

【问题讨论】:

  • 我刚刚在 BSONError.js 中发现了一个导致问题的错误,我正在写一个答案。我认为它与版本无关。

标签: c arrays pointers struct julia


【解决方案1】:

该问题与ccall 无关。它是由this line 引起的,如堆栈跟踪所示。

在 0.4 中,不再有 convert{T}(::Type{Ptr{T}},Array{T}) 函数。

ccall 调用使用(未导出的)unsafe_convert 方法转换其参数(这就是上述代码不会导致错误的原因)。如果您想在用户代码中使用Ptr 对象,最简单的方法是使用pointer 方法。

【讨论】:

  • 您介意详细说明您的最后一句话吗?我(还)不是ccall 和转换方面的专家。
【解决方案2】:

原来 BSONError.jl 有一个错误,

return bytestring(convert(Ptr{Uint8}, bsonError._wrap_[9:end]))

应该是

return bytestring(bsonError._wrap_[9:end])

在 BSONError.jl 的 convert 函数中。也就是因为错误打印有问题,所以无法打印出错误。

解决这个问题,从收到的表单 C 的错误消息中发现正确的 bson 格式是

BSONObject("{\"a\":1}")

创建一个 bson 对象。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
相关资源
最近更新 更多