2016-10-19 25 views
9

Ok, początkowo źle sparaliżowałem moje sformułowanie tego pytania (jest to ponad rok odkąd poważnie napisałem kod C++ i mam dość ograniczone doświadczenie z czystym C), więc Spróbujmy jeszcze raz.prawidłowy sposób deklarowania wskaźników C void w Julii

Niektóre kod C jest napisane, aby oczekiwać, aby zrobić coś jak na poniższym

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

Moje pytanie brzmi: w jaki sposób utworzyć obiekt p w Julii. Teraz wierzę, że odpowiedź będzie

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

Ponadto uważam ten sam kod, ale zamiast z p zadeklarowane jako p = Array(Ptr{Void}, 1) również działa.

Jednak uważam, że całe rozróżnienie pomiędzy Ref i Ptr w Julii jest bardzo mylące, głównie dlatego, że wydają się nawracać między sobą w sposób, którego nie mogę śledzić.

+0

Szczegóły: z 'void * p;' 'p' jest "nowa rzecz"(object). 'create_new_thing (&p);' zezwala na funkcję _assign_ 'p' wartość .. Powodzenia z Julią – chux

+0

Zrozumiałem, powodem, dla którego nie użyłem słowa obiekt jest to, że obawiałem się bycia bardzo konkretnym. powiedzmy niezmienny numeryczny typ: –

+0

W języku C, _object_ to _general_ termin dla "regionu przechowywania danych ... którego zawartość może reprezentować wartości" jak znaki, liczby całkowite, zmiennoprzecinkowe, wskaźniki, tablice, struktury, związki, i stałe.Nic prawie wszystko, co można wskazać poza funkcjami – chux

Odpowiedz

9

Twój kod wygląda na prawie w porządku. Ale bądź ostrożny! Każdy mały błąd, jak to masz tutaj, może powodować usterki segmentacji:

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^

poprawny sposób zrobić to

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^

Najprostszym sposobem, aby zrozumieć, gdzie użycie p i p[] jest myśleć o odpowiednim kodzie C. W C, piszemy

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

Julia obiekty nie mają pierwszej klasy obiektów, takich jak adresy pamięci C zrobić, więc musimy użyć p = Ref{Ptr{Void}}() w Julię, aby uzyskać adres pamięci. Ten obiekt, jako ref, zachowuje się jak &p w C. Oznacza to, że aby uzyskać sam obiekt, p w C, musimy użyć p[] w Julia.

Więc równowartość w Julia jest

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

Pierwsza sygnatura 'ccall' powinna prawdopodobnie również zawierać' Ref {Ptr {Void}} 'zamiast' Ptr {Ptr {Void}} ': http://docs.julialang.org/en/release-0.5/manual/calling-c-and-fortran-code/#passing-pointers-for-modifying-inputs –

+1

@SimonByrne Z mojego punktu widzenia są one dokładnie równoważne w tym przypadku, więc po prostu zachowałem kod PO. –

+1

Myślę, że są one w tej chwili równoważne, ale instrukcja zaleca 'Ref' dla zmiennych wskaźników. –