问题描述
我正在扩展一个使用C库的Julia包.我需要从Julia中调用一些C函数.他们看起来像这样:
I am extending a Julia package that uses a C library. I need to call some C functions from Julia. They look something like this:
struct contained {
int x;
int y;
int z;
};
struct mystruct {
int n;
contained* arr;
};
mystruct* mk_mystruct(int n, contained* arr);
void use_mystruct(mystruct* foo);
我也在Julia中声明了相应的类型:
I have also declared the corresponding types in Julia:
type contained
x::Int64
y::Int64
z::Int64
end
type mystruct
n::Int64
arr::Array{contained, 1}
end
对于以contained*
作为参数的ccall
函数,将contained*
视为Ptr{Int64}
的一切工作正常:
To ccall
functions which take a contained*
as an argument, everything works fine treating the contained*
as Ptr{Int64}
:
con = fill(0, 5, 3);
mys = ccall((:mk_mystruct, "mylib"), Ptr{mystruct}, (Int64, Ptr{Int64}), n, con)
我想这行得通,因为contained
具有与Int64s数组相同的内存布局.这也是在Julia包中其他地方完成的方式.但是我知道检查返回的mystruct
的值的唯一方法是用unsafe_load
取消引用它,这时Julia退出了段错误.在Julia中取消引用指针的正确方法是什么?
I suppose this works because contained
has the same memory layout as an array of Int64s. This is also how it is done elsewhere in the Julia package. But the only way I know to check the value of the returned mystruct
is to dereference it with unsafe_load
, at which point Julia crashes from a segfault. What is the right way to dereference a pointer in Julia?
C库还包含漂亮的打印函数,因此,除了在Julia中取消引用指针之外,我还可以将指针视为不透明的,然后将其传递回此C函数:
The C library also includes pretty-printing functions, so instead of dereferencing the pointer in Julia I could treat the pointer as opaque and pass it back to this C function:
void print_mystruct(mystruct* foo, FILE* outputfile)
在C代码中,用outputfile=stdout
调用.如何使用ccall
进行设置?这显然行不通:
In the C code, this is called with outputfile=stdout
. How would I set this up with ccall
? This obviously does not work:
ccall((:print_mystruct, "mylib"), Void, (Ptr{mystruct}, Ptr{Void}), mys, stdout)
我应该放置什么而不是Ptr{Void}
和stdout
? Julia如何在C接口中实现I/O?
What should I put instead of Ptr{Void}
and stdout
? How does Julia implement I/O in the C interface?
推荐答案
在Julia中声明类型时,必须声明与C:相同的类型.
When you declare the type in Julia, you must declare the same types as C:
type contained
x::Cint
y::Cint
z::Cint
end
type mystruct
n::Cint
arr::Ptr{contained}
end
Julia类型Array{contained, 1}
将对应于C中的jl_value_t*
,而Julia类型Int
将对应于C中的intptr_t
.
The Julia type Array{contained, 1}
would correspond to jl_value_t*
in C and the Julia type Int
would correspond to intptr_t
in C.
我不知道与平台无关的方法来获取stdout
的句柄,因为大多数平台都需要扩展C标头宏来查找真实的符号名称.例如,在macOS上,它被重命名为__stdoutp
:
I don't know of a platform-agnostic way to get a handle to stdout
, as most platforms require expanding a C header macro to find out the real symbol name. For example, on macOS, it gets renamed to __stdoutp
:
julia> unsafe_load(cglobal(:__stdoutp, Ptr{Void}))
Ptr{Void} @0x00007fff751f7348
julia> ccall(:fprintf, Csize_t, (Ptr{Void}, Cstring, Cint...), ans, "hi\n")
hi
0x0000000000000003
您可能有兴趣查看 Clang.jl软件包,该软件包可以自动生成这些定义解析头文件.
You may be interested in checking out the Clang.jl package which can automatically generate these definitions from parsing the header files.
这篇关于Julia-非基本类型的C接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!