我在从 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}
,其中T
是 UInt8
在这种情况下。所以 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/