2017-02-19 101 views
2

我試圖將參數傳遞給使用ctypes的共享庫中的Fortran子例程。現在,這裏是我的簡單的Fortran代碼:使用ctypes將python字符串傳遞給Fortran子例程

MODULE test_module 
INCLUDES 
SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    RETURN 
END SUBROUTINE fstr_test 
END MODULE test_module 

gcc -shared -fPIC -o libtest.o fstr_test.f90 

這似乎做工精細編譯這個,我其實可以加載共享庫在Python 3.這裏的非崩潰代碼:

from ctypes import * 
libtest = cdll.LoadLibrary("libtest.so") 
f = libtest.test_module_MOD__fstr_test 
file = b'wout_li383.nc' 
ierr = c_int(0) 
iopen = c_int(0) 
cfile=c_char_p(b"test_str") 
f(cfile,byref(ierr),byref(iopen)) 

但是,我似乎無法正確傳遞字符串。在上面的表單中,字符串是空的,兩個整數正確地打印到控制檯。基本上,我所取得的唯一進展是讓Python崩潰。我在這裏嘗試瞭解決方案:

Passing string to Fortran DLL using ctypes and Python

,但它似乎並沒有爲我工作,也許是因爲它是Python 2?

例如

f.argtype = [c_char_p,c_int_c_int] 
c = c_char_p(b"test.txt") 
f(c,byref(ierr),byref(iopen)) 

不會崩潰的內核,但字符串是空的。改爲byref:

f.argtype = [c_char_p,c_int_c_int] 
c = c_char_p(b"test.txt") 
f(byref(c),byref(ierr),byref(iopen)) 

同樣的效果。現在,如果我嘗試通過添加length參數來傳遞長度並傳遞它,我會收到一條「Dead Kernel」的消息,我必須重新啓動內核。本身沒有錯誤信息。

f.argtype = [c_char_p,c_int,c_int_c_int] 
file = b'text.txt' 
c = c_char_p(file) 
c_len = c_int(len(file)) 
f(c,byref(c_len),byref(ierr),byref(iopen)) 

希望澄清。我沒有收到錯誤信息,內核剛剛死亡。

+0

鏈接的問題的答案是爲字符串的長度傳遞一個「隱藏的」參數(當不使用C可互操作的字符變量時常用的方法)。你不這樣做? – francescalus

+0

爲什麼它不能工作?錯誤信息?錯誤的結果?給他們看。 –

+0

如果我將字符串長度作爲隱藏變量包含,則內核崩潰。 – Lazer

回答

2

所以有一些問題,其中一個隱藏長度(至少在gfortran未知其他編譯器做什麼時)應該放在參數列表的末尾。你不需要在它按地址要麼不換行字節字符串中c_char_p

在子程序更改IERR變量

SUBROUTINE fstr_test(file_or_extension, ierr, iopen) 
    IMPLICIT NONE 
    INTEGER, INTENT(out) :: ierr 
    INTEGER, OPTIONAL :: iopen 
    CHARACTER(LEN=*), INTENT(in) :: file_or_extension 
    WRITE(6,*) file_or_extension,ierr,iopen 
    ierr=1 
    RETURN 
    END SUBROUTINE fstr_test 

gfortran -shared -fPIC -o libtest.so fstr_test.f90 

然後蟒蛇代碼應該是這樣的:

import ctypes 

lib=ctypes.CDLL("./libtest.so") 
f=getattr(lib,'__test_module_MOD_fstr_test') 

f.argtypes=[ctypes.c_char_p,ctypes.c_int,ctypes.c_int,ctypes.c_int] 
f.restype=None 

x=b'abcdef' 
ierr=ctypes.c_int(0) 
iopen=0 
f(x,ctypes.byref(ierr),iopen,len(x)) 
print(ierr.value) 

雖然我沒有可選的參數工作讓,所以我已經添加了一個空的int,這應該是你傳遞這個字符串並讓它出來。

+0

在你的例子中它應該是'argparse'還是'argtypes'?順便說一句,感謝它似乎工作得很好。 – Lazer

+0

好的,應該是argtypes – Rob