2017-01-18 2 views
1

Quelqu'un peut-il expliquer pourquoi ce ccall fonctionne quand je spécifie explicitement le type, mais Julia échoue avec "error interpreting ccall argument tuple" quand j'utilise typeof pour spécifier le type?Julia typeof in ccall

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 

Si j'imprimer Ptr{typeof(b.eq)} et Ptr{Ptr{Foo}}, ils affichent le même. Si je compare avec is(), ils sont égaux. Quelle est la différence? J'ai également essayé d'attribuer v = typeof(b.eq) à une variable d'abord et ensuite en passant Ptr{v}, mais cela n'a pas aidé.

Répondre

4

typeof est une fonction d'exécution, mais les types d'argument ccall doivent être déterminables statiquement lorsque la fonction est compilée. (sinon, Julia aurait besoin d'insérer une garde autour de chaque ccall pour intercepter les types qui ne correspondent pas, rendant ainsi ccall beaucoup plus lent).

Votre meilleure option est de spécifier un type fixe dans le ccall, comme vous l'avez découvert.

Il est possible d'utiliser un parametric type pour un ou plusieurs arguments dans la déclaration de fonction, ce qui permettra à Julia de compiler une version différente de la fonction (y compris une ccall spécialisée) pour chaque variante du type d'argument:

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 

Cependant, il est peu probable que ce soit la bonne solution sauf si vous modifiez le nom de la fonction C ou si vous passez un pointeur sur une structure qui a une balise de type.

Notez que si vous réfléchissez une structure C avec un pointeur opaque void*, vous pouvez simplement écrire eq::Ptr{Void}.

+0

Ce que j'ai réellement est 'struct opaque_obj **', qui alloue la mémoire dans new_boo et réaffecte le pointeur externe de l'appelant. Le code que j'ai fourni était la seule façon de comprendre comment faire l'appel c - pas nécessairement le meilleur moyen. – Todd

+1

'Ptr {Ptr {Void}}' est également disponible. –