Julia - 具有 struct hack 的 C 类型会导致段错误

Mat*_*ord 3 c struct julia

这个问题是Julia - C interface with nonfundamental types的后续问题,有足够的新信息可以被视为不同的问题。我使用的 C 库有两种这样的类型,以及三种可能的版本mystruct

struct contained {
    int x;
    int y;
    int z;
};
struct mystruct {
    int n;
//original:
//    contained* arr;
//struct hack version 1:
//    contained arr[1];
//struct hack version 2:
      contained arr[];
};
Run Code Online (Sandbox Code Playgroud)

使用原始问题的答案,我定义了以下相应的 Julia 类型,它们可以与 的原始版本一起正常工作mystruct,但不能使用 struct hack 的任何一个版本:

type contained
    x::Cint
    y::Cint
    z::Cint
end
type mystruct
    n::Cint
    arr::Ptr{contained}
end
Run Code Online (Sandbox Code Playgroud)

如果我从 Julia 调用一个 C 函数,它返回 aPtr{mystruct}并将其另存为ms,我可以放置m = unsafe_load(ms)并查看m.n和 指针m.arr,但我只能unsafe_load(m.arr)在原始情况下检查它的值。否则unsafe_load(m.arr)会导致段错误。Julia 中处理包含以这种方式定义的可变长度数组的 C 结构的正确方法是什么?我只会使用mystructwith的原始定义contained *arr,因为它按预期工作,但我也需要适用于其他情况的代码。

Isa*_*ton 5

正如Julia 手册的 C 接口部分中提到的,关于内联类型/结构成员:

不支持未知大小的数组。

但是,可以使用结构体的地址来计算出数组数据的偏移量(就像在 C 中一样),然后使用unsafe_wrap访问该数据。


这是一个完整的例子:

测试.c

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x;
    int y;
    int z;
} contained;

typedef struct {
    int n;
    contained arr[];
} mystruct;

mystruct *return_mystruct() {
    mystruct* ms = malloc(sizeof(mystruct) + 6*sizeof(contained));

    ms->n = 6;

    for (int i=0; i < 6; i++) {
        printf("i: %d\n", i);
        ms->arr[i].x = i+1;
        ms->arr[i].y = i+1;
        ms->arr[i].z = i+1;
    };

    return ms;
}
Run Code Online (Sandbox Code Playgroud)

编译:gcc -shared -o test test.c

朱莉娅:

immutable contained
  x::Cint
  y::Cint
  z::Cint
end
immutable mystruct
  n::Cint
end

ms = ccall((:return_mystruct, "test"), Ptr{mystruct}, ())

n = unsafe_load(ms).n
addr = reinterpret(Ptr{contained}, ms+sizeof(mystruct))
arr = unsafe_wrap(Vector{contained}, addr, n)
Run Code Online (Sandbox Code Playgroud)

笔记:

  • type->immutable以确保布局与C兼容(参见手册)
  • 请注意,该地址必须在任何 Julia 内存引用的生命周期内有效,这通常意味着它必须是堆分配的)