ccall,在签名中使用Array类型调用来自Julia的C中的结构

时间:2015-09-16 17:24:04

标签: c arrays pointers struct julia

我在从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
处理MongoDB查询所需的https://github.com/pzion/LibBSON.jl/blob/master/src/BSONObject.jl LibBSON包中的

,但设置并不是特别重要。重要的是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}

朱莉娅手册http://julia.readthedocs.org/en/latest/manual/calling-c-and-fortran-code/#mapping-c-types-to-julia在“将C类型映射到朱莉娅&#39;部分&#39;比特类型&#39;朱莉娅Array{T,N}应该作为Ptr{T}传递的小节,在这种情况下TUInt8。所以Julia ccall看起来不错,但仍然存在错误信息。这是一个相当棘手的问题,因为它可以防止数据库中更复杂的查询。有关如何解决此ccall问题的任何建议吗?

P.S。请注意,如果您安装Mongo软件包,它将随LibBSON软件包和libbson C库一起提供。

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

事实证明BSONError.jl有一个错误,

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

应该是

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

在BSONError.jl的convert函数中。也就是说,错误无法打印出来,因为错误打印是错误的。

修复了从C表单收到的错误消息,结果证明正确的bson格式是

BSONObject(&#34; {\&#34; \&#34;:1}&#34)

创建一个bson对象。