2017-01-18 12 views
1

typeを明示的に指定するとこのccallが機能する理由を説明できますが、typeofを使用して型を指定すると "エラー解釈ccall引数タプル"でJuliaが失敗しますか?ccallのJulia typeof

type Foo 
end 
type Boo 
    eq::Ptr{Foo} 
    buf::Array{Float32,1} 
    s::Array{UInt8,1} 
end 

function new_boo(p1, p2, p3, p4, p5) 
    b = Boo(C_NULL,zeros(p1*2),zeros(div(p1,2))) 
    eqref = Ref{typeof(b.eq)}(C_NULL) 
    res = ccall((:myfunc, "mydll.dll"), stdcall, Cint, (Ptr{typeof(b.eq)}, Int32, Int8, Int8, Int8, Int8), 
       eqref, p1, p2, p3, p4, p5) 
    b.eq = eqref[] 
    b 
end 

私はPtr{typeof(b.eq)}Ptr{Ptr{Foo}}を印刷する場合、それらは同じを表示します。私がis()と比較すると、それらは等しいです。違いは何ですか?私もv = typeof(b.eq)を変数に代入してからPtr{v}を渡そうとしましたが、それは役に立ちませんでした。

答えて

4

typeofはランタイム関数ですが、関数のコンパイル時にccall引数型を静的に決定する必要があります。 (さもなければ、Juliaは、ccallの周りにガードを挿入して、マッチしないタイプをキャッチして、ccallをもっと遅くする必要があります)。

ベストプラクティスは、発見したとおり、ccallに固定タイプを指定することです。

ジュリアは引数の型の各変異体について(特殊ccall含む)機能の異なるバージョンをコンパイルすることを可能にする関数宣言、1つ以上の引数のparametric typeを使用することが可能である:

function new_boo{T}(p1::T, p2, p3, p4, p5) 
    ... 
    res = ccall((:myfunc, "mydll.dll"), stdcall, Cint, (Ptr{T}, Int32, Int8, Int8, Int8, Int8), eqref, p1, p2, p3, p4, p5) 
end 

ただし、C関数名を変更するか、型タグを持つ構造体にポインタを渡さない限り、これは正しい解決策ではありません。

void*スタイルの不透明ポインタを使用してC構造体を反映する場合は、eq::Ptr{Void}と書くことができます。

+0

私が実際に持っているのは、 'struct opaque_obj **'です。これは、new_booにメモリを割り当て、呼び出し元の外部ポインタを再割り当てします。私が提供したコードは、必ずしも最善の方法ではなく、Cコールの作成方法を理解する唯一の方法でした。 – Todd

+1

'Ptr {Ptr {Void}}'も利用できます。 –