我正在尝试使用Julia的ccall
函数与C库进行交互。所有类型和指针都是正确的,下面的函数调用成功返回正确的答案(为简洁起见,此处未显示变量定义和设置)。
ccall((:vDSP_convD, libacc), Void,
(Ptr{T}, Int64, Ptr{T}, Int64, Ptr{T}, Int64, UInt64, UInt64),
x_padded, 1, pointer(K, Ksize), -1, result, 1, Rsize, Ksize)
但是,如果我希望将函数名称生成为符号,然后将其用作ccall
的参数,则会失败。
fname = symbol(string("vDSP_conv", "D"))
ccall((fname , libacc), Void,
(Ptr{T}, Int64, Ptr{T}, Int64, Ptr{T}, Int64, UInt64, UInt64),
x_padded, 1, pointer(K, Ksize), -1, result, 1, Rsize, Ksize)
错误是:
ERROR: LoadError: TypeError: conv: in ccall: first argument not a
pointer or valid constant expression, expected Ptr{T},
got Tuple{Symbol,ASCIIString}
如果我打印这两个命名版本中的每一个的类型,我得
julia> println(typeof(:vDSP_convD))
Symbol
julia> println(typeof(fname))
Symbol
有没有办法让它发挥作用?我猜测我必须将它包装在一个宏或@eval
中才能完成这项工作,但我很好奇为什么上述功能无法正常工作?
非常感谢任何帮助!
编辑
我最终将它包装在@eval
块中以使其工作;但是,我仍然对后端逻辑感到好奇,为什么上面的语法不起作用(为什么它有时会将符号解释为指针,然后不是其他时间)
答案 0 :(得分:9)
ccall
实际上不是一个函数 - 它是一种使用C ABI转换为C函数调用的语法形式。要发出对C函数的调用,您需要能够静态地解析函数的地址 - 这就是此要求的来源。请注意,在C和Julia中,您还可以使用变量函数指针调用函数。在Julia中,有几种方法可以获得这样的指针,通常使用dlopen
和dlsym
。 ccall
不会做的是通过非常量名称解析函数:这在C中是不可能的(没有构建自己的查找表);在Julia中,你可以通过使用eval
来解决这个问题,但是这样做会产生编译器开销。这就是为什么ccall
不会自动执行此操作的原因:例如,您不希望冒着在循环中意外引入编译器开销的风险。