Julia - 具有非基本类型的 C 接口 [英] Julia - C interface with nonfundamental types

查看:18
本文介绍了Julia - 具有非基本类型的 C 接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在扩展一个使用 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 具有与 Int64 数组相同的内存布局.这也是 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 库还包括漂亮的打印函数,因此我可以将指针视为不透明指针并将其传递回此 C 函数,而不是取消对 Julia 中的指针的引用:

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 对应于 intptr_t 在 C 中.

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
")
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 接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆