2011-11-24 56 views
3

我試圖讓Python使用Fortran DLL(通過referance調用)。運行Fortran 90代碼時,它運行良好,但不適用於Python;它只會提供「訪問衝突」錯誤或「調用的參數不足」。Ctypes Python訪問違規<> Fortran DLL

的Python代碼:

from ctypes import * 
mydll = cdll.LoadLibrary("test.dll") 

# This function works. 
print mydll.XIT() # prints 0 

mydll.GetInfo.argtypes = [POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_char_p)] 

rm = c_int() 
rf = c_int() 
vm = (c_int * 5)() 
vf = (c_int * 5)() 
np = c_int(14) 
p = (c_int * 14)() 
filename = "test" 
fn = c_char_p(filename) 
nc = c_int(len(filename)) # length of string. (Hidden argument in Fortran) 

# throws insufucient arguments 
print mydll.GetInfo(rm,rf,vm,vf,np,p,fn,nc) 

# throws access violation 
print mydll.GetInfo(byref(rm),byref(rf),byref(vm),byref(vf),byref(np),byref(p),byref(fn),byref(nc)) 

的FORTRAN90代碼:

program test 
    implicit none 
    integer, parameter :: np = 14 
    integer :: rm, rf 
    integer, dimension(5) :: vm, vf 
    integer, dimension(np) :: p 
    character(len=80) :: fn 
    interface 
    integer function GetInfo(rm, rf, vm, vf, np, p, fn) 
    !dec$ attributes dllimport, stdcall, reference, decorate, alias:'GetInfo' :: GetInfo 
     implicit none 
     character(len=*), intent(in) :: fn 
     integer, intent(in) :: np 
     integer, intent(out) :: rm,rf 
     integer, intent(out), dimension(5) :: vm,vf 
     integer, intent(out), dimension(np) :: p 
    end function GetInfo 
    end interface 
    fn = "test" 
    print *, GetInfo(rm, rf, vm, vf, np, p, fn) 
end program test 

編輯: 我修改我的代碼,到現在還沒通字符串的長度作爲參考。我已將cdll切換到windll,並刪除了雙POINTER和byref()用法。另外,c_char_p已經是一個指針,所以它不需要POINTER。

+0

你知道,這不像你的編譯器要你更多地編譯更長的變量名。只是說... –

+0

@Stefano Fortran是別人的代碼,並且寫下了很長名字的傳統。在邊界的另一邊使用相同的名稱是有意義的。 –

+0

@David Heffernan:原來的名字很短,你可以用它們作爲前綴。 – eryksun

回答

4

我不知道你的Fortran編譯器的約定所以我會用一些基本點,而不是具體回答:

  1. 你調用約定不匹配。 Fortran代碼指定stdcall,ctypes代碼指定cdecl。你需要讓它們相匹配。例如,將ctypes更改爲使用windll而不是cdll
  2. 您確定POINTER(c_char_p)是對的嗎?這是一個指向空終止字符串的指針。我認爲你可能在Python的末尾有一個額外的間接層,但我不是100%確定的。
  3. @eryksun在評論中聲明隱式字符串長度參數是按值傳遞的,而不是按引用傳遞的。

否則我看不出什麼錯,雖然我對Fortran一無所知,所以我不能擔保。

如果我是你,我會將這個權利切回到一個傳遞一個int參數的簡單函數。然後我將添加一個int數組,並檢查是否可以爲這樣的參數傳輸數據。然後移動到一個字符串。不要從頭開始嘗試這樣一個複雜的參數列表,因爲您只是給自己太多的潛在缺陷,並且很難知道先看哪裏。

+0

這不是我的DLL,所以不幸的是,有沒有更簡單的函數使用:\我會嘗試與windll! POINTER()是我試圖使其工作的方式之一,因爲我看到一些論壇帖子,它的成功。 – Kols

+0

沒有probs。用適當簡單的函數編寫你自己的Fortran DLL。同時修復調用約定,看看是否有幫助。 –

+0

@ user1064136:字符串的長度通過值傳遞,而不是通過引用傳遞。 – eryksun