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'))