Python ctypes 将结构字段中的指针传递给 Fortran 派生类型
Python ctypes pass pointer in structure field to Fortran derived types
我想制作一个可变大小的数组来传递给 Fortran DLL 并获取结果(通过引用),以便我可以直接获取值。
在 Fortran 代码中,我使用可分配变量,我认为它就像指向分配地址的指针。
我可以做如下但我不知道如何在结构上做:
test = POINTER(c_double)()
sim.structtest(input, byref(test))
test
在Fortran中的定义是
real(kind=8), allocatable, dimension (:) :: test
allocate(test(1))
原代码:
Python代码(structtest.py):
from ctypes import *
import sys
import os
sim = cdll.LoadLibrary("struct.so")
class Input( Structure ):
_fields_ = [( "a", c_double * 1 ),
( "b", c_double )]
class Output( Structure ):
_fields_ = [( "a", c_double ),
( "b", POINTER(c_double) )] #-> don't know how to do
def main():
input = Input()
output = Output()
input.a[0] = 1
input.b = 2
sim.structtest(input, byref(output))
Fortran 代码 (struct.f90):
subroutine structtest(input, output) bind(c, name='structtest')
USE ISO_C_BINDING
IMPLICIT NONE
!define input structure
TYPE T_INPUT
!real*8, allocatable :: a(:)
real(kind=8) :: a(1)
real(kind=8) :: b
END TYPE T_INPUT
!define output structure
TYPE T_OUTPUT
real(kind=8) :: a
real(kind=8), allocatable, dimension (:) :: b
END TYPE T_OUTPUT
!define a variable "input" with structure "INPUT"
TYPE (T_INPUT), value :: input
TYPE (T_OUTPUT) :: output
allocate(output%d(1))
output%b(1) = 5
PRINT *, output%d(1)
我将 Fortran 编译为 DLL,如下所示:
ifort -shared -fPIC -static-intel -o struct.so struct.f90
我将 Python 执行为:
python structtest.py
我得到结果:
*** Error in `python': free(): corrupted unsorted chunks: 0x0000000001f7af00 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fc9027f57e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fc9027fe37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fc90280253c]
/lib/x86_64-linux-gnu/libc.so.6(__open_catalog+0xe8)[0x7fc9027b2008]
/lib/x86_64-linux-gnu/libc.so.6(catopen+0x4c)[0x7fc9027b1c2c]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for__issue_diagnostic+0x11e)[0x7fc90147a77e]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for_allocate+0x303)[0x7fc90146b9a3]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(structtest+0xae)[0x7fc90146b16e]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call_unix64+0x4c)[0x7fc901757e40]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call+0x2eb)[0x7fc9017578ab]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(_ctypes_callproc+0x48f)[0x7fc9019673df]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(+0x11d82)[0x7fc90196bd82]
python(PyObject_Call+0x43)[0x4b0c93]
python(PyEval_EvalFrameEx+0x602f)[0x4c9f9f]
python(PyEval_EvalFrameEx+0x5e0f)[0x4c9d7f]
python(PyEval_EvalCodeEx+0x255)[0x4c2705]
python(PyEval_EvalCode+0x19)[0x4c24a9]
python[0x4f19ef]
python(PyRun_FileExFlags+0x82)[0x4ec372]
python(PyRun_SimpleFileExFlags+0x191)[0x4eaaf1]
python(Py_Main+0x6c8)[0x49e208]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fc90279e830]
python(_start+0x29)[0x49da59]
======= Memory map: ========
00400000-006e9000 r-xp 00000000 08:01 525090 /usr/bin/python2.7
008e8000-008ea000 r--p 002e8000 08:01 525090 /usr/bin/python2.7
008ea000-00961000 rw-p 002ea000 08:01 525090 /usr/bin/python2.7
00961000-00984000 rw-p 00000000 00:00 0
01f10000-01ff6000 rw-p 00000000 00:00 0 [heap]
7fc8fc000000-7fc8fc021000 rw-p 00000000 00:00 0
7fc8fc021000-7fc900000000 ---p 00000000 00:00 0
7fc901246000-7fc90125c000 r-xp 00000000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90125c000-7fc90145b000 ---p 00016000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90145b000-7fc90145c000 rw-p 00015000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90145c000-7fc901504000 r-xp 00000000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc901504000-7fc901704000 ---p 000a8000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc901704000-7fc90170a000 rw-p 000a8000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc90170a000-7fc901752000 rw-p 00000000 00:00 0
7fc901752000-7fc901759000 r-xp 00000000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901759000-7fc901958000 ---p 00007000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901958000-7fc901959000 r--p 00006000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901959000-7fc90195a000 rw-p 00007000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc90195a000-7fc901978000 r-xp 00000000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901978000-7fc901b77000 ---p 0001e000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b77000-7fc901b78000 r--p 0001d000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b78000-7fc901b7c000 rw-p 0001e000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b7c000-7fc901e54000 r--p 00000000 08:01 529135 /usr/lib/locale/locale-archive
7fc901e54000-7fc901f5c000 r-xp 00000000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc901f5c000-7fc90215b000 ---p 00108000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215b000-7fc90215c000 r--p 00107000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215c000-7fc90215d000 rw-p 00108000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215d000-7fc902176000 r-xp 00000000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902176000-7fc902375000 ---p 00019000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902375000-7fc902376000 r--p 00018000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902376000-7fc902377000 rw-p 00019000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902377000-7fc902379000 r-xp 00000000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902379000-7fc902578000 ---p 00002000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902578000-7fc902579000 r--p 00001000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902579000-7fc90257a000 rw-p 00002000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc90257a000-7fc90257d000 r-xp 00000000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90257d000-7fc90277c000 ---p 00003000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277c000-7fc90277d000 r--p 00002000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277d000-7fc90277e000 rw-p 00003000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277e000-7fc90293e000 r-xp 00000000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc90293e000-7fc902b3e000 ---p 001c0000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b3e000-7fc902b42000 r--p 001c0000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b42000-7fc902b44000 rw-p 001c4000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b44000-7fc902b48000 rw-p 00000000 00:00 0
7fc902b48000-7fc902b60000 r-xp 00000000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902b60000-7fc902d5f000 ---p 00018000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d5f000-7fc902d60000 r--p 00017000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d60000-7fc902d61000 rw-p 00018000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d61000-7fc902d65000 rw-p 00000000 00:00 0
7fc902d65000-7fc902d8b000 r-xp 00000000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902dc5000-7fc902f7b000 rw-p 00000000 00:00 0
7fc902f86000-7fc902f87000 rw-p 00000000 00:00 0
7fc902f87000-7fc902f88000 rwxp 00000000 00:00 0
7fc902f88000-7fc902f8a000 rw-p 00000000 00:00 0
7fc902f8a000-7fc902f8b000 r--p 00025000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902f8b000-7fc902f8c000 rw-p 00026000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902f8c000-7fc902f8d000 rw-p 00000000 00:00 0
7ffc38bde000-7ffc38bff000 rw-p 00000000 00:00 0 [stack]
7ffc38cd8000-7ffc38cda000 r--p 00000000 00:00 0 [vvar]
7ffc38cda000-7ffc38cdc000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
可分配组件的 so-called 描述符在内存中的布局是特定于 Fortran 处理器的。对于可分配的数组组件,它总是不仅仅是一个内存地址。您需要查阅 Fortran 处理器的文档以了解有关描述符的详细信息。依赖于描述符布局的代码本质上是特定于处理器的。
可以在标题为 Handling Fortran Array Descriptors 的部分中找到当前版本的英特尔编译器的相关文档。
Fortran 2018 的当前草案提供了与可分配虚拟参数进行互操作的额外工具,但仍然存在特定于平台的特征。
(在显示的代码中,您使用了内部模块 ISO_C_BINDING,但代码似乎没有从中引用任何内容...)
谢谢大家,
下面是 Python 将多维数组传递给 Fortran
的工作示例
python代码:
from ctypes import *
import ctypes
import sys
import os
import numpy as np
sim = cdll.LoadLibrary(os.path.dirname(os.path.abspath(__file__)) + "/lib/struct.so")
class Param( Structure ):
pass
class Result( Structure ):
pass
def main():
x = 2
y = 3
z = 4
Param._fields_ = [( "len_x", c_int ),
( "len_y", c_int ),
( "len_z", c_int ),
( "c", POINTER(c_double)),
( "d", POINTER(c_double * x)),
( "e", POINTER(c_double * x * y))]
Result._fields_ = [( "len_x", c_int ),
( "len_y", c_int ),
( "len_z", c_int ),
( "f", POINTER(c_double)),
( "g", POINTER(c_double * x)),
( "h", POINTER(c_double * x * y))]
param = Param()
result = Result()
cc = (c_double * x)()
dd = ( (c_double * x) * y )()
ee = ( ( ( (c_double * x) * y ) * z ) )()
#[x]
cc[0] = 10.0
cc[1] = 20.0
#[y][x]
dd[0][0] = 10.0
dd[1][0] = 20.0
dd[2][0] = 30.0
dd[0][1] = 40.0
dd[1][1] = 50.0
dd[2][1] = 60.0
#[z][y][x]
ee[0][0][0] = 1.0
ee[1][0][0] = 2.0
ee[2][0][0] = 3.0
ee[0][1][0] = 4.0
ee[1][1][0] = 5.0
ee[2][1][0] = 6.0
param.len_x = x
param.len_y = y
param.len_z = z
param.c = cc
param.d = dd
param.e = ee
sim.structtest(byref(param), byref(result))
#[x]
print "1D"
print result.f[0]
print result.f[1]
#[y][x]
print "2D"
print result.g[0][0]
print result.g[1][0]
print result.g[2][0]
print result.g[0][1]
print result.g[1][1]
print result.g[2][1]
#[z][y][x]
print "3D"
print result.h[0][0][0]
print result.h[1][0][0]
print result.h[2][0][0]
print result.h[0][1][0]
print result.h[1][1][0]
print result.h[2][1][0]
if __name__ == "__main__":
result = main()
fortran 代码:
subroutine structtest(param, result) bind(c, name="structtest")
use, intrinsic :: ISO_C_BINDING
implicit none
type, BIND(C) :: args
integer (C_INT) :: len_x
integer (C_INT) :: len_y
integer (C_INT) :: len_z
type (C_PTR) :: c
type (C_PTR) :: d
type (C_PTR) :: e
end type args
type, BIND(C) :: output
integer (C_INT) :: len_x
integer (C_INT) :: len_y
integer (C_INT) :: len_z
type (C_PTR) :: f
type (C_PTR) :: g
type (C_PTR) :: h
end type output
type (args), intent(in):: param
type (output), intent(out):: result
real (C_DOUBLE), pointer :: arg_array_c(:)
real (C_DOUBLE), pointer :: arg_array_d(:,:)
real (C_DOUBLE), pointer :: arg_array_e(:,:,:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_f(:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_g(:,:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_h(:,:,:)
! Associate c_array with an array allocated in C
call C_F_POINTER (param%c, arg_array_c, [param%len_x] )
call C_F_POINTER (param%d, arg_array_d, [param%len_x,param%len_y] )
call C_F_POINTER (param%e, arg_array_e, [param%len_x,param%len_y,param%len_z] )
![x]
print *,"1D"
print *,arg_array_c(1)
print *,arg_array_c(2)
![x][y]
print *,"2D"
print *,arg_array_d(1,1)
print *,arg_array_d(1,2)
print *,arg_array_d(1,3)
print *,arg_array_d(2,1)
print *,arg_array_d(2,2)
print *,arg_array_d(2,3)
![x][y][z]
print *,"3D"
print *,arg_array_e(1,1,1)
print *,arg_array_e(1,1,2)
print *,arg_array_e(1,1,3)
print *,arg_array_e(1,2,1)
print *,arg_array_e(1,2,2)
print *,arg_array_e(1,2,3)
! Allocate an array and make it available in C
result%len_x = param%len_x
result%len_y = param%len_y
result%len_z = param%len_z
ALLOCATE (result_array_f(result%len_x))
ALLOCATE (result_array_g(result%len_x, result%len_y))
ALLOCATE (result_array_h(result%len_x, result%len_y, result%len_z))
result%f = c_loc(result_array_f)
result%g = c_loc(result_array_g)
result%h = c_loc(result_array_h)
![x]
result_array_f(1) = arg_array_c(1)
result_array_f(2) = arg_array_c(2)
![x][y]
result_array_g(1,1) = arg_array_d(1,1)
result_array_g(1,2) = arg_array_d(1,2)
result_array_g(1,3) = arg_array_d(1,3)
result_array_g(2,1) = arg_array_d(2,1)
result_array_g(2,2) = arg_array_d(2,2)
result_array_g(2,3) = arg_array_d(2,3)
![x][y][z]
result_array_h(1,1,1) = arg_array_e(1,1,1)
result_array_h(1,1,2) = arg_array_e(1,1,2)
result_array_h(1,1,3) = arg_array_e(1,1,3)
result_array_h(1,2,1) = arg_array_e(1,2,1)
result_array_h(1,2,2) = arg_array_e(1,2,2)
result_array_h(1,2,3) = arg_array_e(1,2,3)
end
输出:
1D
10.0000000000000
20.0000000000000
2D
10.0000000000000
20.0000000000000
30.0000000000000
40.0000000000000
50.0000000000000
60.0000000000000
3D
1.00000000000000
2.00000000000000
3.00000000000000
4.00000000000000
5.00000000000000
6.00000000000000
1D
10.0
20.0
2D
10.0
20.0
30.0
40.0
50.0
60.0
3D
1.0
2.0
3.0
4.0
5.0
6.0
我想制作一个可变大小的数组来传递给 Fortran DLL 并获取结果(通过引用),以便我可以直接获取值。
在 Fortran 代码中,我使用可分配变量,我认为它就像指向分配地址的指针。
我可以做如下但我不知道如何在结构上做:
test = POINTER(c_double)()
sim.structtest(input, byref(test))
test
在Fortran中的定义是
real(kind=8), allocatable, dimension (:) :: test
allocate(test(1))
原代码:
Python代码(structtest.py):
from ctypes import *
import sys
import os
sim = cdll.LoadLibrary("struct.so")
class Input( Structure ):
_fields_ = [( "a", c_double * 1 ),
( "b", c_double )]
class Output( Structure ):
_fields_ = [( "a", c_double ),
( "b", POINTER(c_double) )] #-> don't know how to do
def main():
input = Input()
output = Output()
input.a[0] = 1
input.b = 2
sim.structtest(input, byref(output))
Fortran 代码 (struct.f90):
subroutine structtest(input, output) bind(c, name='structtest')
USE ISO_C_BINDING
IMPLICIT NONE
!define input structure
TYPE T_INPUT
!real*8, allocatable :: a(:)
real(kind=8) :: a(1)
real(kind=8) :: b
END TYPE T_INPUT
!define output structure
TYPE T_OUTPUT
real(kind=8) :: a
real(kind=8), allocatable, dimension (:) :: b
END TYPE T_OUTPUT
!define a variable "input" with structure "INPUT"
TYPE (T_INPUT), value :: input
TYPE (T_OUTPUT) :: output
allocate(output%d(1))
output%b(1) = 5
PRINT *, output%d(1)
我将 Fortran 编译为 DLL,如下所示:
ifort -shared -fPIC -static-intel -o struct.so struct.f90
我将 Python 执行为:
python structtest.py
我得到结果:
*** Error in `python': free(): corrupted unsorted chunks: 0x0000000001f7af00 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fc9027f57e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fc9027fe37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fc90280253c]
/lib/x86_64-linux-gnu/libc.so.6(__open_catalog+0xe8)[0x7fc9027b2008]
/lib/x86_64-linux-gnu/libc.so.6(catopen+0x4c)[0x7fc9027b1c2c]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for__issue_diagnostic+0x11e)[0x7fc90147a77e]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for_allocate+0x303)[0x7fc90146b9a3]
/home/mingster/simGeo.docker/simgeo/lib/struct.so(structtest+0xae)[0x7fc90146b16e]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call_unix64+0x4c)[0x7fc901757e40]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call+0x2eb)[0x7fc9017578ab]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(_ctypes_callproc+0x48f)[0x7fc9019673df]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(+0x11d82)[0x7fc90196bd82]
python(PyObject_Call+0x43)[0x4b0c93]
python(PyEval_EvalFrameEx+0x602f)[0x4c9f9f]
python(PyEval_EvalFrameEx+0x5e0f)[0x4c9d7f]
python(PyEval_EvalCodeEx+0x255)[0x4c2705]
python(PyEval_EvalCode+0x19)[0x4c24a9]
python[0x4f19ef]
python(PyRun_FileExFlags+0x82)[0x4ec372]
python(PyRun_SimpleFileExFlags+0x191)[0x4eaaf1]
python(Py_Main+0x6c8)[0x49e208]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fc90279e830]
python(_start+0x29)[0x49da59]
======= Memory map: ========
00400000-006e9000 r-xp 00000000 08:01 525090 /usr/bin/python2.7
008e8000-008ea000 r--p 002e8000 08:01 525090 /usr/bin/python2.7
008ea000-00961000 rw-p 002ea000 08:01 525090 /usr/bin/python2.7
00961000-00984000 rw-p 00000000 00:00 0
01f10000-01ff6000 rw-p 00000000 00:00 0 [heap]
7fc8fc000000-7fc8fc021000 rw-p 00000000 00:00 0
7fc8fc021000-7fc900000000 ---p 00000000 00:00 0
7fc901246000-7fc90125c000 r-xp 00000000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90125c000-7fc90145b000 ---p 00016000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90145b000-7fc90145c000 rw-p 00015000 08:01 38797837 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc90145c000-7fc901504000 r-xp 00000000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc901504000-7fc901704000 ---p 000a8000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc901704000-7fc90170a000 rw-p 000a8000 08:01 51643749 /home/mingster/simGeo.docker/simgeo/lib/struct.so
7fc90170a000-7fc901752000 rw-p 00000000 00:00 0
7fc901752000-7fc901759000 r-xp 00000000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901759000-7fc901958000 ---p 00007000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901958000-7fc901959000 r--p 00006000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc901959000-7fc90195a000 rw-p 00007000 08:01 526635 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4
7fc90195a000-7fc901978000 r-xp 00000000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901978000-7fc901b77000 ---p 0001e000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b77000-7fc901b78000 r--p 0001d000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b78000-7fc901b7c000 rw-p 0001e000 08:01 30543353 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
7fc901b7c000-7fc901e54000 r--p 00000000 08:01 529135 /usr/lib/locale/locale-archive
7fc901e54000-7fc901f5c000 r-xp 00000000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc901f5c000-7fc90215b000 ---p 00108000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215b000-7fc90215c000 r--p 00107000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215c000-7fc90215d000 rw-p 00108000 08:01 38797852 /lib/x86_64-linux-gnu/libm-2.23.so
7fc90215d000-7fc902176000 r-xp 00000000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902176000-7fc902375000 ---p 00019000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902375000-7fc902376000 r--p 00018000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902376000-7fc902377000 rw-p 00019000 08:01 38797934 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fc902377000-7fc902379000 r-xp 00000000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902379000-7fc902578000 ---p 00002000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902578000-7fc902579000 r--p 00001000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc902579000-7fc90257a000 rw-p 00002000 08:01 38797927 /lib/x86_64-linux-gnu/libutil-2.23.so
7fc90257a000-7fc90257d000 r-xp 00000000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90257d000-7fc90277c000 ---p 00003000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277c000-7fc90277d000 r--p 00002000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277d000-7fc90277e000 rw-p 00003000 08:01 38797825 /lib/x86_64-linux-gnu/libdl-2.23.so
7fc90277e000-7fc90293e000 r-xp 00000000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc90293e000-7fc902b3e000 ---p 001c0000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b3e000-7fc902b42000 r--p 001c0000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b42000-7fc902b44000 rw-p 001c4000 08:01 38797811 /lib/x86_64-linux-gnu/libc-2.23.so
7fc902b44000-7fc902b48000 rw-p 00000000 00:00 0
7fc902b48000-7fc902b60000 r-xp 00000000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902b60000-7fc902d5f000 ---p 00018000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d5f000-7fc902d60000 r--p 00017000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d60000-7fc902d61000 rw-p 00018000 08:01 38797898 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fc902d61000-7fc902d65000 rw-p 00000000 00:00 0
7fc902d65000-7fc902d8b000 r-xp 00000000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902dc5000-7fc902f7b000 rw-p 00000000 00:00 0
7fc902f86000-7fc902f87000 rw-p 00000000 00:00 0
7fc902f87000-7fc902f88000 rwxp 00000000 00:00 0
7fc902f88000-7fc902f8a000 rw-p 00000000 00:00 0
7fc902f8a000-7fc902f8b000 r--p 00025000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902f8b000-7fc902f8c000 rw-p 00026000 08:01 38797787 /lib/x86_64-linux-gnu/ld-2.23.so
7fc902f8c000-7fc902f8d000 rw-p 00000000 00:00 0
7ffc38bde000-7ffc38bff000 rw-p 00000000 00:00 0 [stack]
7ffc38cd8000-7ffc38cda000 r--p 00000000 00:00 0 [vvar]
7ffc38cda000-7ffc38cdc000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
可分配组件的 so-called 描述符在内存中的布局是特定于 Fortran 处理器的。对于可分配的数组组件,它总是不仅仅是一个内存地址。您需要查阅 Fortran 处理器的文档以了解有关描述符的详细信息。依赖于描述符布局的代码本质上是特定于处理器的。
可以在标题为 Handling Fortran Array Descriptors 的部分中找到当前版本的英特尔编译器的相关文档。
Fortran 2018 的当前草案提供了与可分配虚拟参数进行互操作的额外工具,但仍然存在特定于平台的特征。
(在显示的代码中,您使用了内部模块 ISO_C_BINDING,但代码似乎没有从中引用任何内容...)
谢谢大家,
下面是 Python 将多维数组传递给 Fortran
的工作示例python代码:
from ctypes import *
import ctypes
import sys
import os
import numpy as np
sim = cdll.LoadLibrary(os.path.dirname(os.path.abspath(__file__)) + "/lib/struct.so")
class Param( Structure ):
pass
class Result( Structure ):
pass
def main():
x = 2
y = 3
z = 4
Param._fields_ = [( "len_x", c_int ),
( "len_y", c_int ),
( "len_z", c_int ),
( "c", POINTER(c_double)),
( "d", POINTER(c_double * x)),
( "e", POINTER(c_double * x * y))]
Result._fields_ = [( "len_x", c_int ),
( "len_y", c_int ),
( "len_z", c_int ),
( "f", POINTER(c_double)),
( "g", POINTER(c_double * x)),
( "h", POINTER(c_double * x * y))]
param = Param()
result = Result()
cc = (c_double * x)()
dd = ( (c_double * x) * y )()
ee = ( ( ( (c_double * x) * y ) * z ) )()
#[x]
cc[0] = 10.0
cc[1] = 20.0
#[y][x]
dd[0][0] = 10.0
dd[1][0] = 20.0
dd[2][0] = 30.0
dd[0][1] = 40.0
dd[1][1] = 50.0
dd[2][1] = 60.0
#[z][y][x]
ee[0][0][0] = 1.0
ee[1][0][0] = 2.0
ee[2][0][0] = 3.0
ee[0][1][0] = 4.0
ee[1][1][0] = 5.0
ee[2][1][0] = 6.0
param.len_x = x
param.len_y = y
param.len_z = z
param.c = cc
param.d = dd
param.e = ee
sim.structtest(byref(param), byref(result))
#[x]
print "1D"
print result.f[0]
print result.f[1]
#[y][x]
print "2D"
print result.g[0][0]
print result.g[1][0]
print result.g[2][0]
print result.g[0][1]
print result.g[1][1]
print result.g[2][1]
#[z][y][x]
print "3D"
print result.h[0][0][0]
print result.h[1][0][0]
print result.h[2][0][0]
print result.h[0][1][0]
print result.h[1][1][0]
print result.h[2][1][0]
if __name__ == "__main__":
result = main()
fortran 代码:
subroutine structtest(param, result) bind(c, name="structtest")
use, intrinsic :: ISO_C_BINDING
implicit none
type, BIND(C) :: args
integer (C_INT) :: len_x
integer (C_INT) :: len_y
integer (C_INT) :: len_z
type (C_PTR) :: c
type (C_PTR) :: d
type (C_PTR) :: e
end type args
type, BIND(C) :: output
integer (C_INT) :: len_x
integer (C_INT) :: len_y
integer (C_INT) :: len_z
type (C_PTR) :: f
type (C_PTR) :: g
type (C_PTR) :: h
end type output
type (args), intent(in):: param
type (output), intent(out):: result
real (C_DOUBLE), pointer :: arg_array_c(:)
real (C_DOUBLE), pointer :: arg_array_d(:,:)
real (C_DOUBLE), pointer :: arg_array_e(:,:,:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_f(:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_g(:,:)
real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_h(:,:,:)
! Associate c_array with an array allocated in C
call C_F_POINTER (param%c, arg_array_c, [param%len_x] )
call C_F_POINTER (param%d, arg_array_d, [param%len_x,param%len_y] )
call C_F_POINTER (param%e, arg_array_e, [param%len_x,param%len_y,param%len_z] )
![x]
print *,"1D"
print *,arg_array_c(1)
print *,arg_array_c(2)
![x][y]
print *,"2D"
print *,arg_array_d(1,1)
print *,arg_array_d(1,2)
print *,arg_array_d(1,3)
print *,arg_array_d(2,1)
print *,arg_array_d(2,2)
print *,arg_array_d(2,3)
![x][y][z]
print *,"3D"
print *,arg_array_e(1,1,1)
print *,arg_array_e(1,1,2)
print *,arg_array_e(1,1,3)
print *,arg_array_e(1,2,1)
print *,arg_array_e(1,2,2)
print *,arg_array_e(1,2,3)
! Allocate an array and make it available in C
result%len_x = param%len_x
result%len_y = param%len_y
result%len_z = param%len_z
ALLOCATE (result_array_f(result%len_x))
ALLOCATE (result_array_g(result%len_x, result%len_y))
ALLOCATE (result_array_h(result%len_x, result%len_y, result%len_z))
result%f = c_loc(result_array_f)
result%g = c_loc(result_array_g)
result%h = c_loc(result_array_h)
![x]
result_array_f(1) = arg_array_c(1)
result_array_f(2) = arg_array_c(2)
![x][y]
result_array_g(1,1) = arg_array_d(1,1)
result_array_g(1,2) = arg_array_d(1,2)
result_array_g(1,3) = arg_array_d(1,3)
result_array_g(2,1) = arg_array_d(2,1)
result_array_g(2,2) = arg_array_d(2,2)
result_array_g(2,3) = arg_array_d(2,3)
![x][y][z]
result_array_h(1,1,1) = arg_array_e(1,1,1)
result_array_h(1,1,2) = arg_array_e(1,1,2)
result_array_h(1,1,3) = arg_array_e(1,1,3)
result_array_h(1,2,1) = arg_array_e(1,2,1)
result_array_h(1,2,2) = arg_array_e(1,2,2)
result_array_h(1,2,3) = arg_array_e(1,2,3)
end
输出:
1D
10.0000000000000
20.0000000000000
2D
10.0000000000000
20.0000000000000
30.0000000000000
40.0000000000000
50.0000000000000
60.0000000000000
3D
1.00000000000000
2.00000000000000
3.00000000000000
4.00000000000000
5.00000000000000
6.00000000000000
1D
10.0
20.0
2D
10.0
20.0
30.0
40.0
50.0
60.0
3D
1.0
2.0
3.0
4.0
5.0
6.0