2016-10-19 3 views
9

Хорошо, я изначально плохо прищурил свою формулировку этого вопроса (прошло уже больше года, так как я серьезно написал код на C++, и у меня довольно ограниченный опыт с чистым C), поэтому давай попробуем снова.Правильный способ объявить C void указатели в Julia

Часть кода C пишется ожидать вас сделать что-то вроде следующего

void* p; 
create_new_thing(&p); //p is now a new thing 
do_stuff_to_thing(p); //something happened to p 

Мой вопрос в том, как создать объект p в Джулию. Сейчас я считаю, что ответ будет

p = Ref{Ptr{Void}}() 
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p) 
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p) 

Кроме того, я считаю, один и тот же код, но с p объявлен вместо этого как p = Array(Ptr{Void}, 1) работает.

Я все же различаю между Ref и Ptr в Джулии очень запутанным, главным образом потому, что они, похоже, преобразуются друг в друга способами, которые я не могу отслеживать.

+0

деталь: с 'ничтожной * р,', 'p' это "новая вещь"(объект). 'create_new_thing (&p);' позволяет функции _assign_ 'p' значение. Удачи с Джулией. – chux

+0

Понял, причина, по которой я не использовал объект слова, заключается в том, что я опасался быть очень конкретным. Можно было бы это сделать, скажем, неизменный числовой тип. –

+0

В C _объект_ является _general_ термином для «области хранения данных ...», содержимое которой может представлять значения «как символы, целые числа, плавающие точки, указатели, массивы, структуры, объединения, и константы. Почти все, на что можно обратить внимание, кроме функций. – chux

ответ

9

Ваш код выглядит почти штраф. Но будь осторожен! Любая небольшая ошибка, как и тот, который вы здесь, может привести к ошибке сегментации:

p = Ref{Ptr{Void}}() 
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p) 
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p) 
             # error here^

Правильный способ сделать это

p = Ref{Ptr{Void}}() 
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p) 
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p[]) 
              # fixed^

Самый простой способ понять, где использовать p и p[] является думать о соответствующем C-коде. В C, мы пишем

void *p; 
create_new_thing(&p) 
do_stuff_to_thing(p) 

объекты Julia не имеют адреса памяти первого класса как объекты C сделать, поэтому мы должны использовать p = Ref{Ptr{Void}}() в Джулию, чтобы получить адрес памяти. Этот объект, как ref, ведет себя как &p в C. Это означает, что для получения самого объекта p в C нам нужно использовать p[] в Julia.

Так эквивалент в Юле

p = Ref{Ptr{Void}}()     # this p corresponds to &p in C 
ccall(:create_new_thing, ..., p)  # like &p 
ccall(:do_stuff_to_thing, ..., p[]) # like *(&p); that is, like p 
+1

Первой подписи 'ccall' должно быть также' Ref {Ptr {Void}} 'вместо' Ptr {Ptr {Void}} ': http://docs.julialang.org/en/release-0.5/manual/calling-c-and-fortran-code/#passing-pointers-for-modifying-inputs –

+1

@SimonByrne По моему мнению, они в точности эквивалентны в этом случае, поэтому я просто сохранил код OP. –

+1

Я думаю, что они эквивалентны на данный момент, но руководство рекомендует 'Ref' для изменяемых указателей. –