c++和python調用fortran77生成dll同理,但須要注意subroutine名稱要大寫,否則不認html
Fortran(90)代碼以下:python
! fortranDLLExample.f90 ! ! FUNCTIONS/SUBROUTINES exported from fortranDLLExample.dll: ! fortranDLLExample - subroutine FUNCTION ABZERO(P) bind(C,name="ABZERO") !DEC$ ATTRIBUTES DLLEXPORT :: ABZERO !DEC$ ATTRIBUTES VALUE :: P integer, INTENT(IN) :: P integer :: ABZERO integer :: result1 ! Examle calculation result1 = P - 273 print *, "The p==", P, ";" print *, "The p-273 [", result1, "]" ABZERO = result1 RETURN END FUNCTION FUNCTION ABZERO_FLOAT(P) bind(C,name="ABZERO_FLOAT") !DEC$ ATTRIBUTES DLLEXPORT :: ABZERO_FLOAT !DEC$ ATTRIBUTES VALUE :: P real, INTENT(IN) :: P real :: ABZERO_FLOAT real :: result1 ! Examle calculation result1 = P - 273.15 print *, "The p==", P, ";" print *, "The p-273 [", result1, "]" ABZERO_FLOAT = P - 273.15 RETURN END FUNCTION FUNCTION sum(length1, P) bind(C,name="sum") !DEC$ ATTRIBUTES DLLEXPORT :: sum implicit none integer::length1 real, dimension(*):: P real :: sum integer::i print *, "The length1==", length1, ";" sum =0.0 do i = 1,length1 ! sum the array elements sum = sum + p(i) PRINT *,p(i) end do RETURN END FUNCTION subroutine func01( a ) bind(C,name="func01") !DEC$ ATTRIBUTES DLLEXPORT :: func01 implicit none character(len=1), dimension(90) , intent(in) :: a character(len=30), dimension(3) :: b integer*4 :: count,i,j count=1 do j=1,3 b(J)='' do I=1,30 b(J)=trim(b(J))//a(count) count=count+1 enddo enddo print * print *, "char length = ", len(b(1)), len(b(2)), len(b(3)) print *, "raw a(1) : [", b(1), "]" print *, "raw a(2) : [", b(2), "]" print *, "raw a(3) : [", b(3), "]" print *, "trim : [", trim(b(1)), "] [", trim(b(2)), "] [", trim(b(3)), "]" end FUNCTION SUMANDTIMES(P, length1, Q) bind(C,name="SUMANDTIMES") !DEC$ ATTRIBUTES DLLEXPORT :: SUMANDTIMES implicit none integer::length1 real, dimension(*):: P real :: SUMANDTIMES, Q integer::i print *, "The length1==", length1, ";" SUMANDTIMES =0.0 do i = 1,length1 ! sum the array elements SUMANDTIMES = SUMANDTIMES + p(i) * Q PRINT *,p(i) end do RETURN END FUNCTION FUNCTION array2by2(P, row, col) bind(C,name="array2by2") !DEC$ ATTRIBUTES DLLEXPORT :: array2by2 USE ISO_C_BINDING implicit none integer::row, col, i, j, array2by2 !real,DIMENSION(row*col):: real P(*) real PP(row, col) print *, "---->row-----", row print *, "---->col-----", col do i=1,row do j=1,col PP(i,j) = P((i-1)*row+j) P((i-1)*row+j) = PP(i,j) * 100 print *, PP(i,j), i, j, (i-1)*row+j end do print *, "----row-----", i end do array2by2 = 0 RETURN END FUNCTION
Python調用代碼以下(dll放在py文件的同一目錄)c++
# coding=utf-8 from _ctypes import byref from ctypes import cdll, c_int, c_float import ctypes my_dll = cdll.LoadLibrary('fortranDLLExample.dll') result = my_dll.ABZERO(c_int(324)) print "my_dll.ABZERO(c_int(324))==", result, type(result) my_dll.ABZERO_FLOAT.restype = c_float # 要設置返回值的類型,否則默認會返回int型,致使數據混亂 result = my_dll.ABZERO_FLOAT(c_float(500.44)) print "my_dll.ABZERO_FLOAT(c_float(500.44))", result, type(result) # tip:dll.addf.argtypes = (c_float, c_float) # addf 有兩個形參,都是 float 類型。雖然也能夠用數組設置,可是元祖的效率更高 FloatArray = c_float * 5 ia = FloatArray(5.32, 1.12, 7.321, 33.12, 99.3) for i in ia: print i my_dll.sum.restype = c_float result = my_dll.sum(byref(c_int(len(ia))), byref(ia)) print "dll.sum == ", result FloatArray = c_float * 3 ia2 = FloatArray(1.1, 2.2, 3.3) my_dll.SUMANDTIMES.restype = c_float result = my_dll.SUMANDTIMES(byref(ia2), byref(c_int(len(ia2))), byref(c_float(100.1))) print "dll.SUMANDTIMES == ", type(result), result # 出現win32不是有效的應用程序bug的時候,記得在fortran編輯器選擇好x86或x64,版本要和python的位數對應上 d = ctypes.create_string_buffer("abcde67890b234567 " "waeofijo " "awoijewfawfe ", size=90) my_dll.func01(d) j_table = (c_float * 16)(1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.4, 3.1, 3.2, 3.3, 3.4, 4.1, 4.2, 4.3, 4.4) # 給力 my_dll.array2by2(byref(j_table), byref(c_int(4)), byref(c_int(4))) for i in j_table: print i, print "--------------------- 操做完後的結果 ---------------------" h_table = (c_float * 16)(91.1, 51.2, 1.35, 1.45, 92.1, 52.2, 2.35, 2.45, 93.1, 53.2, 3.35, 3.45, 94.1, 54.2, 4.35, 4.45) # 給力 my_dll.array2by2(byref(h_table), byref(c_int(4)), byref(c_int(4))) for i in h_table: print i, print "--------------------- 操做完後的結果 ---------------------" my_dll.array2by2(byref(j_table), byref(c_int(4)), byref(c_int(4))) for i in j_table: print i, print "默認傳給dll的是指針,所以在fortran中若是動了地址裏面的內容,那麼反映到python上也會跟着改變"
輸出結果以下:express
The p== 324 ; The p-273 [ 51 ] my_dll.ABZERO(c_int(324))== 51 <type 'int'> The p== 500.4400 ; The p-273 [ 227.2900 ] my_dll.ABZERO_FLOAT(c_float(500.44)) 227.290008545 <type 'float'> 5.32000017166 1.12000000477 7.32100009918 33.1199989319 99.3000030518 The length1== 5 ; 5.320000 1.120000 7.321000 33.12000 99.30000 dll.sum == 146.180999756 The length1== 3 ; 1.100000 2.200000 3.300000 dll.SUMANDTIMES == <type 'float'> 660.66003418 char length = 30 30 30 raw a(1) : [abcde67890b234567 ] raw a(2) : [waeofijo ] raw a(3) : [awoijewfawfe ] trim : [abcde67890b234567] [waeofijo] [awoijewfawfe] ---->row----- 4 ---->col----- 4 1.100000 1 1 1 1.200000 1 2 2 1.300000 1 3 3 1.400000 1 4 4 ----row----- 1 2.100000 2 1 5 2.200000 2 2 6 2.300000 2 3 7 2.400000 2 4 8 ----row----- 2 3.100000 3 1 9 3.200000 3 2 10 3.300000 3 3 11 3.400000 3 4 12 ----row----- 3 4.100000 4 1 13 4.200000 4 2 14 4.300000 4 3 15 4.400000 4 4 16 ----row----- 4 110.0 120.000007629 130.0 140.0 209.999984741 220.0 230.0 240.000015259 310.0 320.0 330.0 340.0 410.0 419.999969482 430.000030518 440.0 --------------------- 操做完後的結果 --------------------- ---->row----- 4 ---->col----- 4 91.10000 1 1 1 51.20000 1 2 2 1.350000 1 3 3 1.450000 1 4 4 ----row----- 1 92.10000 2 1 5 52.20000 2 2 6 2.350000 2 3 7 2.450000 2 4 8 ----row----- 2 93.10000 3 1 9 53.20000 3 2 10 3.350000 3 3 11 3.450000 3 4 12 ----row----- 3 94.10000 4 1 13 54.20000 4 2 14 4.350000 4 3 15 4.450000 4 4 16 ----row----- 4 9110.0 5120.0 135.0 145.0 9210.0 5220.0 234.999984741 245.0 9310.0 5320.0 335.0 345.0 9410.0 5420.0 435.0 444.999969482 --------------------- 操做完後的結果 --------------------- ---->row----- 4 ---->col----- 4 110.0000 1 1 1 120.0000 1 2 2 130.0000 1 3 3 140.0000 1 4 4 ----row----- 1 210.0000 2 1 5 220.0000 2 2 6 230.0000 2 3 7 240.0000 2 4 8 ----row----- 2 310.0000 3 1 9 320.0000 3 2 10 330.0000 3 3 11 340.0000 3 4 12 ----row----- 3 410.0000 4 1 13 420.0000 4 2 14 430.0000 4 3 15 440.0000 4 4 16 ----row----- 4 11000.0 12000.0009766 13000.0 14000.0 20999.9980469 22000.0 23000.0 24000.0019531 31000.0 32000.0 33000.0 34000.0 41000.0 41999.9960938 43000.0039062 44000.0 默認傳給dll的是指針,所以在fortran中若是動了地址裏面的內容,那麼反映到python上也會跟着改變
bind(C,name="RUN_S_ENTERFUNC")不是必須的,加上bind後傳入字符串有可能報錯數組
當使用不定長度數組或者字符串的時候,應該去掉!DEC$ ATTRIBUTES VALUE :: P以免編譯器反覆提示你要給數組分配一個固定的長度編輯器
The character length of a dummy argument with the VALUE attribute must be an initialization expression. [INPUTFILE]函數
關於fortran數組:工具
Syntactically, assumed shape used colons (:) instead of
an asterisk in the dimension declaration. The difference in meaning
is exactly the subject in question - assumed shape arrays automatically
get their shape information passed, whereas assumed size arrays basically
get nothing but a starting address passed. visual-studiohttp://computer-programming-forum.com/49-fortran/f2a81d00123cad00.htm字體
運行python遇到這個錯誤 error: Unable to find vcvarsall.bat 能夠這麼解決:
報錯緣由:在生成的時候,編譯器從%PythonInstallPath%\distutils\msvc9compiler.py裏的219行find_vcvarsall(version)函數中找不到vcvarsall.bat文件。
更具體的緣由是,msvc9compiler.py從sys.version裏提取MSVC的版本號,可是在註冊表中並無根據版本號找到vcvarsall.bat,在系統的環境變量中也沒有找到版本號對應的路徑。後來我根據版本號,在環境變量中添加了路徑,但由於msvc9compiler.py主要是針對VS2008和VS2010所作的路徑識別,所以仍是不能正確地找到vcvarsall.bat。
解決方法:直接在find_vcvarsall(version)函數中返回vcvarsall.bat的絕對路徑。
https://blog.csdn.net/sad_sugar/article/details/73743863
Tip:運行.bat後,至關於添加了vs各類工具的環境變量,咱們可使用dumpbin /symbols xxx.lib來查看lib中有多少function供咱們使用
在安裝VS 2015期間遇到這麼一個問題(即便是去官網下載的版本也會遇到https://www.visualstudio.com/zh-hans/vs/older-downloads/):
setup detected an issue during the operation.
「安裝程序檢測到一個問題......」
解決方法是:
找到C:\Windows\Fonts目錄,
備份fonts下面全部的字體
而後刪除C:\Windows\Fonts下面全部的字體(系統字體若是刪除不了的,那麼就留着,一些字體集提示警告不要刪除的,也留着)
而後再安裝vs2015就OK了!
這個確實問題很詭異,但就是這麼解決的:https://stackoverflow.com/questions/33622151/setup-detected-an-issue-during-visual-studio-community-edition-2015-installation
當出現這個錯誤的時候Visual Studio cannot debug because a debug target has not been specified或者cannot start debugging because the debug target is missing
(在編譯dll的時候尤爲容易出現,能夠選擇一個exe來debug)
編輯VS裏的fortran時,若是咱們但願開啓轉跳到定義功能,在這裏設置:
新bug解決方案:
有人發覺使用python3的時候調用錯誤,debug半天發覺進到dll裏的字符串不對。查找緣由,最終發覺是python二、3字符串表述問題。python2字符串默認是ascii的str,而python3是unicode,而通常c語言、fortran語言接收的是char或char數組,所以應該轉爲ascii,使用語句:
import ctypes DLL_PATH = 'C:./Test2.dll' lib = ctypes.cdll.LoadLibrary(DLL_PATH) lib.printString('abc'.encode('ascii'))