2015-02-24 57 views
2

我有一個大的現有Fortran95代碼。它使用Fortran-C互操作性和浮點數組

real(dp), dimension(num) :: array 

來聲明數組。

我想在一些C代碼加入,我發現我可以通過寫C函數接口和聲明數組作爲

use iso_c_binding 
real(c_double), allocatable, target :: array(:) 

做到這一點我有工作,其調用C-功能FORTRAN功能

call myfunction(c_loc(array)); 

需要什麼將real(dp)數組傳遞給myfunction?顯然,我需要從它製作一個C指針(怎麼樣?)。除複製數組外還有其他方法嗎?是否有可能確保兩種類型確實是指兼容的雙精度數據塊?最重要的是該解決方案必須與GNU編譯器一起工作。請注意,在現有的Fortran代碼中無處不在替換real(dp)real(c_double)對我來說不是一種選擇。

如果沒有替代拷貝整個數組,我怎麼會在界面上做這個正常嗎?

回答

4

首先,我假設你在一個模塊中定義DP作爲參數的地方。你可以簡單地在該模塊中使用

integer, parameter :: dp = c_double 

(並有if (dp /= c_double) stop "Bletchful sytem"地方

在C和Fortran語言之間的數組是這樣的:

module foo 
    use iso_c_binding 
    private 
    public :: bar 
    interface 
    subroutine bar(a,n) bind(C) 
     import 
     real(kind=c_double), dimension(*), intent(inout) :: a 
     integer(c_size_t), value, intent(in) :: n 
    end subroutine bar 
    end interface 
end module foo 

你的C函數,然後將

void bar(double *a, size_t n) 

編輯:

調用然後從Fortran語言的C函數將在路

program main 
    use iso_c_binding 
    use foo 
    real(c_double), dimension(10) :: a 
    call bar(a,size(a,kind=c_size_t)) 
    print *,a 
end program main 

編輯2:

如果你真的想拷入/拷出的每個時間做,你可以做類似

subroutine bar2(array) 
    real(kind=c_double), intent(inout), dimension(:) :: array 
    real(kind=c_double), dimension(size(array)) :: a 
    a = array ! Copy in 
    call bar(a,size(a,kind=c_size_t)) 
    array = a ! Copy out 
    end subroutine bar2 
end module foo 

但我不知道爲什麼這是必要的。

編輯3:

如果你害怕C和Fortran數據類型之間的不匹配,你可以寫一個通用的包裝來解決這個問題。這是可能的樣子:

module foo 
    use iso_c_binding 
    implicit none 
    private 
    public :: bar 
    interface 
    subroutine bar_double(a,n) bind(C) 
     import 
     real(kind=c_double), dimension(*), intent(inout) :: a 
     integer(c_size_t), value, intent(in) :: n 
    end subroutine bar_double 
    end interface 

    interface 
    subroutine bar_float(a,n) bind(C) 
     import 
     real(kind=c_float), dimension(*), intent(inout) :: a 
     integer(c_size_t), value, intent(in) :: n 
    end subroutine bar_float 
    end interface 

    interface bar 
    module procedure bar_aux_double, bar_aux_float 
    end interface bar 
contains 
    subroutine bar_aux_double (a) 
    real(kind=c_double), dimension(:), intent(inout) :: a 
    call bar_double (a, size(a,kind=c_size_t)) 
    end subroutine bar_aux_double 

    subroutine bar_aux_float (a) 
    real(kind=c_float), dimension(:), intent(inout) :: a 
    call bar_float (a, size(a,kind=c_size_t)) 
    end subroutine bar_aux_float 
end module foo 

主程序則可能看起來像

program main 
    use foo 
    integer, parameter :: dp = selected_real_kind(15) 
    integer, parameter :: sp = selected_real_kind(6) 
    real(dp), dimension(10) :: a_dp 
    real(sp), dimension(10) :: a_sp 
    call bar(a_dp) 
    call bar(a_sp) 
    print *,a_dp,a_sp 
end program main 

,你不要做任何提及ISO_C_BINDING可言。如果沒有dp或sp的包裝函數,編譯將因缺少通用過程而失敗。

+0

另一種可能性,取決於其他代碼結構:'use,intrinsic :: iso_c_binding,只有:dp => c_double'。 – francescalus 2015-02-24 14:57:22

+0

謝謝,我考慮過這個。不幸的是,數組的聲明出現在不同的地方,形式稍有不同。我不太確定副作用是否會發生。我現在正考慮複製整個數組的蠻力方法。在你的模塊foo(基本上就是我所擁有的)中,我將如何添加一個執行復制的函數並調用接口子例程,使其在外部可見? (With contains?) – highsciguy 2015-02-24 15:05:02

+0

編輯2:假設我不改變現有fortran中的數組類型,並且能夠用真實(dp)類型的參數調用bar2(這就是爲什麼我不會這麼做),這是行不通的,因爲數組的聲明是不兼容的,所以在複製時如何在不同類型之間進行轉換? – highsciguy 2015-02-24 15:43:58

1

如果您使用模塊,在Fortran中混合使用dpc_double時不要太擔心。在檢查過程接口時,編譯器會投訴的極不可能的情況是selected_real_kind(15, 307) /= c_double。否則,它會看到類型數字是一致的,它並不關心你如何調用類型常量(除了聲明可互操作的過程時)。

+0

我最初的問題恰恰是,編譯器抱怨說,當C程序的接口和我不知道如何告訴它轉換/忽略錯誤。 – highsciguy 2015-02-25 11:34:04

+0

只需在互操作接口中使用'c_double'並在其他地方使用'dp'。如果模塊中包含所有內容,編譯器會檢查它是否正確。 – 2015-02-25 11:37:57

+0

這不是一個錯誤,只是我想的一個警告。 – 2015-02-25 11:38:30