签名中带有数组类型的 ccall 从 Julia 调用 C 中的结构

标签 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

https://github.com/pzion/LibBSON.jl/blob/master/src/BSONObject.jl LibBSON 包需要处理 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_指的是以下struct在C中:

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有问题吗?

附注请注意,如果您安装 Mongo 软件包,它会附带 LibBSON 软件包和 libbson C 库。

最佳答案

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

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

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

关于签名中带有数组类型的 ccall 从 Julia 调用 C 中的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32614963/

相关文章:

c - C语言中的一种非视觉频率直方图

具有预定义大小的 C++ 数组作为成员变量和内存泄漏

javascript - 使用数组访问视频 URL 并在视频标签中输出

c - string 没有以 NULL 结尾,但仍然表现正常,为什么?

c - 指向 Const Char 的指针

python - 如何解析C头文件?

c - 如何从随机字节开始生成一个区间内的整数随机值

arrays - 如何使用索引在数组类型中递增 std_logic_vector?超高清描述语言

将指针地址转换为 char 数组并使其成为小端

c - 将 sizeof() 与普通数组和 garray 一起使用