准备windows下使用ccall调用fortran写dll,遇到了些问题,请求大家提供帮助。
fortran使用vs+intel ifortran编译。
第一个问题:如何使用ccall调用fortran中的动态数组
在fortran代码中大量使用了ALLOCATE分配的动态数组。
示例代码如下:
SUBROUTINE Init2( InitM ) bind(C,name="Init2")
!DEC$ ATTRIBUTES DLLEXPORT :: Init2
REAL(SELECTED_REAL_KIND( 6, 30 )) , DIMENSION(:,:), ALLOCATABLE, INTENT(INOUT) :: InitM
ALLOCATE( InitM(3,3) )
InitM(1:3,1) = (/ 1.1, 2.1, 3.1 /)
InitM(1:3,2) = (/ 1.2, 2.2, 3.2 /)
InitM(1:3,3) = (/ 1.3, 2.3, 3.3 /)
END SUBROUTINE Init2
如果使用下面这种形式进行调用
ccall(init2,Cvoid,(Ptr(T),),InitM)
InitM需要Julia分配好内存空间,调用动态数组的时候就会和fortran中的分配产生冲突,产生如下错误:
forrtl: severe (151): allocatable array is already allocated
请问各位,有没有什么方法可以获取到fortran中分配的指针,并读取数组?
第二个问题是,如何使用VS attach到Julia进程进行dll调试
使用vs尝试对dll进行调试,但是附加julia进程后,dll调试无法进入断点,没有加载符号,请问如何解决这个问题。
非常感谢!
试了一下也是 无效值、Fortran runtime error: Attempting to allocate already allocated variable 'initm'
和各种段错误。
我总觉得既然都动态内存分配了,看上去也没用 InitM
传进去的值。
就不能没输入直接返回么? (没学过 fortran 可能理解有误)
要不你再看看:调用 C 和 Fortran 代码 · Julia中文文档
我想的是像
julia> t = ccall((:clock, "libc"), Int32, ())
2292761
这样直接返回的。
跟你比较像的是传数组进去的
julia> A = [1.3, -2.7, 4.4, 3.1]
4-element Array{Float64,1}:
1.3
-2.7
4.4
3.1
julia> ccall(:qsort, Cvoid, (Ptr{Cdouble}, Csize_t, Csize_t, Ptr{Cvoid}),
A, length(A), sizeof(eltype(A)), mycompare_c)
julia> A
4-element Array{Float64,1}:
-2.7
1.3
3.1
4.4
他这个是在原数组上进行修改。
也没动态分配。
再就没找到比较相似的例子了。
读取fortran数组的可能解决方法:
思路: fortran中传递的都是指针。在Julia中新建一个空指针,该空指针指向Float32类型的指针。该值被传递给fortran函数,并被修改为函数内数组的指针
实现如下:
···Julia
u = Ref{Ptr{Float32}}
ccall(init2,Cvoid,(Ref{Ptr{Float32}},),u)
a = unsafe_wrap(Array{Float32,2}, u, (3,3))
···
但是奇怪的是,该程序在atom可以顺利运行,但是在32位1.1 repl下报错,直接退出,在64位1.0.2 repl下可以正常运行,可能存在bug。
还可以采用
···Julia
unsafe_load(Ptr{Float32}(u)
···
一个一个读,这个函数比较稳定,不会报错
fortran只能传指针,而且在函数中会有很多个动态数组,无法只返回一个
fortran 编 DLL 的时候也调成 32位的,得对应才能正常调,跟和用 C 调一样。
1 个赞
这个已经注意到了,测试的是对应的版本,如果不对应,dll载入就不成功
这里似乎没有必要用 Ref
:
u = Ptr{Float32}(C_NULL)
GC.@preserve u begin
ccall(init2,Cvoid,(Ref{Float32},),u)
a = unsafe_wrap(Array{Float32,2}, u, (3,3))
end
Roger
9
注意ccall是使用的C的API调用Fortran,函数名称后面要加下划线,例如:gemm → gemm_
Gnimuc
10
他好像用了 bind(C,name="Init2")
这样mangling就和C一样了。
1 个赞