| 
 | 
 
 本帖最后由 Labradog 于 2016-9-7 12:46 编辑  
 
各位好,前段时间发过一个python利用f2py调用fortran的帖子,下面回复的@pasuka兄弟建议我用Ctypes或是cffi,后来自己了解了一下,综合对比了一下,确实Ctypes更好用。现在有一个小问题,想跟各位请教一下。Fortran代码如下。 
 
[Fortran] syntaxhighlighter_viewsource syntaxhighlighter_copycode !*****************************************************
!   随机数模块:
!      通过重载分别定义针对数组以及int的过程
!
!*****************************************************
module rand_m
    implicit none
    interface randi            ! 过程重载
        module procedure randi_ar   ! 数组
        module procedure randi_in   ! int
    end interface
    contains
    !****************************************
        subroutine randi_ar(int_min,int_max,rand_arr)
        ! 输入:下界,上界,随机数变量--数组
        ! 输出:随机数变量--数组
            implicit none
            
            integer,intent(in)::int_min
            integer,intent(in)::int_max
            integer,intent(out),dimension(:)::rand_arr
            ! 局部变量
            real,allocatable,dimension(:)::temp
            if (.not. allocated(temp)) allocate(temp(size(rand_arr)))
            call random_seed()
            call random_number(temp)
            rand_arr=abs(int_max-int_min)*temp+min(int_min,int_max)
            ! 返回rand_arr:随机数组            
        end subroutine randi_ar
        subroutine randi_in(int_min,int_max,rand_int)
        ! 输入:下界,上界,随机数变量--int
        ! 输出:随机数变量--int
            implicit none
            integer,intent(in)::int_min
            integer,intent(in)::int_max
            integer,intent(out)::rand_int
            ! 局部变量
            real::temp
            call random_seed()
            call random_number(temp)
            rand_int=abs(int_max-int_min)*temp+min(int_min,int_max)
            ! 返回rand_int:随机数--int    
        end subroutine randi_in
end module rand_m
module OM_module
use,intrinsic::iso_c_binding
use rand_m
implicit none
contains
    subroutine rand_nucle(arr,nucle_num,n1,n2)
    !dec$ attributes dllexport,decorate,alias:"rand_nucle" :: rand_nucle
        implicit none
            integer(kind=c_int),intent(in),value::n1,n2,nucle_num
        integer(kind=c_int),intent(out),dimension(n1,n2)::arr
            integer::nval=1
        integer,allocatable,dimension(:)::temp_index  ! 二维数组两个索引,不需要改动
        real::i,j
        if (.not. allocated(temp_index)) allocate(temp_index(2))    ! 二维数组两个索引,数字2不需要改动       
    
        do while (nval<=nucle_num)
            call randi(1,n1,temp_index(1))
            call randi(1,n2,temp_index(2))
                
            if (arr(temp_index(1),temp_index(2))<=0) then   ! 注意一定是小于等于,只有小于会一直执行条件语句
                call randi(1,180,arr(temp_index(1),temp_index(2)))
                nval=nval+1
            end if                                
        end do
        deallocate(temp_index)
        end subroutine rand_nucle
end module OM_module
!*****************************************************
program test
    use OM_module
    implicit none
    integer,dimension(5,5)::arr
    integer::n1,n2,n3
    arr=0
    n1=5
    n2=5
    n3=2
    write(*,*) arr
    write(*,*) "*************"
    call rand_nucle(arr,n3,n1,n2)
    write(*,*) arr
end program 
代码主要是在一个全0二位数组中随机生成几个正整数。 
Test之后证明Fortran代码没得问题,不管写的怎么样,反正能实现我的想法。 
fortran 命令行编译dll:ifort /dll test.F90 生成test1.dll。 
 
Python代码如下: 
[Python] syntaxhighlighter_viewsource syntaxhighlighter_copycode #! /usr/bin/env python
#coding=utf-8
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import *
# shape of 2d array
n1,n2 = 10,10
n3=3
# create an empty 2d array
data = np.zeros(shape=(n1,n2),dtype='int64',order='f')
flib = load_library("test1.dll","./")
flib.argtypes = [ndpointer(dtype='int64',ndim=2),c_int,c_int,c_int]
flib.rand_nucle(data.ctypes.data,n3,n1,n2)
print "*"*80
print data 
 
从python中传入一个全0二维矩阵,运算完后返回,运行之后矩阵变成了如下图: 
显然有两个数字太大了,完全不对。我在Fortran中设定的是1-180之间的正整数,在fortran中test也正常。为何python调用之后成了这个样子,百思不得其解,还请各位帮忙看看。 
PS:Fcode兄弟提醒后把Python中int64改成int就OK了,我会继续想怎么让ifort默认int64。改后得到的结果在第二张图片上。 
 
 
 |   
 
 
 
 |