2017-01-18 4 views
1

Может кто-нибудь объяснить, почему этот ccall работает, когда я явно указываю тип, но Julia терпит неудачу с "интерпретацией ошибок ccall аргумент tuple", когда я использую typeof для указания типа?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 

Если я печатаю Ptr{typeof(b.eq)} и Ptr{Ptr{Foo}}, они показывают то же самое. Если сравнивать с is(), они равны. Какая разница? Я также попытался присвоить v = typeof(b.eq) переменной сначала, а затем передать Ptr{v}, но это не помогло.

ответ

4

typeof - это функция времени выполнения, но типы ccall должны быть статически определены при компиляции функции. (в противном случае Джулии нужно было бы вставить охранник вокруг каждого ccall, чтобы поймать неправильно подобранные типы, делая ccall намного медленнее).

Ваш лучший вариант - указать фиксированный тип в ccall, как вы обнаружили.

Можно использовать parametric type для одного или нескольких аргументов в объявлении функции, которая позволит Джулии составить другую версию функции (в том числе специализированной ccall) для каждого варианта типа аргумента:

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 или не передаете указатель на какую-либо структуру, у которой есть тег типа.

Обратите внимание, что если вы отражаете структуру C с помощью указателя opaque void*, вы можете просто написать eq::Ptr{Void}.

+0

У меня на самом деле есть «struct opaque_obj **», который выделяет память в new_boo и переназначает внешний указатель вызывающего. Код, который я предоставил, был единственным способом понять, как сделать вызов c - не обязательно лучший способ. – Todd

+1

'Ptr {Ptr {Void}}' также доступен. –

Смежные вопросы