2016-10-25 4 views
1

この質問は、別の質問とみなされるのに十分な新しい情報で、Julia - C interface with nonfundamental typesのフォローアップです。私はmystructの三つの可能なバージョンで、このような二つのタイプがありますCライブラリを使用:Julia-C types with struct hack原因segfault

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[]; 
}; 

元の質問から答えを使用して、私は、元のバージョンで正常に動作し、以下の対応ジュリア・タイプを定義しています

type contained 
    x::Cint 
    y::Cint 
    z::Cint 
end 
type mystruct 
    n::Cint 
    arr::Ptr{contained} 
end 

私はPtr{mystruct}を返し、msとして保存ジュリアからC関数を呼び出す場合、私はm = unsafe_load(ms)を入れてm.nとポインタを見ることができます:mystructではなく、構造体のハックを使用していずれかのバージョンのですが、元のケースではunsafe_load(m.arr)の値しか確認できません。それ以外の場合はunsafe_load(m.arr)がsegfaultを引き起こします。この方法で定義された可変長配列を含むC構造体を扱うJuliaの正しい方法は何ですか?私はmystructの元の定義だけをcontained *arrと使用しますが、これは期待どおりに動作するためですが、他の場合にも機能するコードが必要です。

答えて

4

インラインタイプ/構造体のメンバについては、C interface section of the Julia manualで述べたように:不明サイズの

配列はサポートされていません。

しかし、(ちょうどCのように)アレイデータへのオフセットを把握するために構造体のアドレスを使用し、次いでunsafe_wrapを使用してそのデータにアクセスすることが可能です。 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) 

注:使用してコンパイル

test.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; 
} 

:ここ


は完全な例である

  • type - >immutableアドレスは一般記憶手段に任意ジュリア参照の寿命に対して有効でなければならないこと
  • 音符を(マニュアル参照)レイアウトはC互換性があることを保証するためにヒープ割り当てされている必要があります)
+0

segfaultの結果として記述したのは、実際には_not_segfaultの場合です。次のコードは、C構造体が 'contained * arr'で定義されているときに、' contains arr [1] 'または' contained arr [] 'でセグメンテーションされたときに期待される出力を出します: ' ms = ccall(:mkmystruct、 Ptr {mystruct}、...) '; 'm = unsafe_load(ms)'; 'n = m.n'; 'arr = [unsigned_load(m.arr、i)in i for 1:n]'; しかし、 'arr = unsafe_wrap(Array、m.arr、m。n) 'と' arr = unsafe_wrap(配列、ms + sizeof(Cint)、m.n) 'はsegfaultsになります。 –

+0

私は例を追加しました。 –

+0

完全な例をありがとう。ここでは、 'mystruct'はJuliaに関する限り' arr'を持っていません。他の 'ccall'で' 'free''になるまで、' 'arr''のメモリが何かによって上書きされないという保証はありますか? –

関連する問題