2015-09-22 42 views
2

問題說明

我的代碼的主要部分是C(從Python調用)。 C部分調用Fortran編寫的函數。使用錯誤代碼和帶有錯誤描述的錯誤字符串傳播可能的錯誤。傳播錯誤字符串:Fortran> C

問題是,我似乎無法獲得正確的接口來在Fortran中編寫字符串並在C中讀取/複製/操作它。下面的代碼概述了我想要執行的操作,帶有* ... *標記的註釋表示在哪裏需要擴展。

Ç

// global variable: read from Python if an error is encountered 
char* error_string; 

// template for the Fortan-subroutine 
void fortran_calculation_(double* , int*); 


int heavy_calculation(double* x) 
{ 

    int error_code; 


    // ... some code ... 


    // * should accept and write "error_string" * 
    fortran_calculation_(x , &error_code); 

    if (error_code) 
    { 
    error_string = "TO BE WRITTEN BY FORTRAN > REMOVE!!"; 
    return 1; 
    } 


    // ... some code ... 


    return 0; 

} 

的Fortran

subroutine fortran_calculation_(x,error_code) 

implicit none 

! * include "error_string" as argument * 
real*8 :: x 
integer :: error_code 


! ... some code ... 


if (...) then 
    ! * write "error_string" * 
    error_code = 1 
    return 
end if 


return 
end subroutine 

我試過很多東西,但我似乎無法得到它的工作...

+1

你的錯誤字符串是否需要全局,或者它可以作爲參數傳遞給你的Fortran例程? – Gilles

+0

對於傳遞字符串,也看到這個問題:http:// stackoverflow。com/q/9972743/577108 – haraldkl

+0

也可以作爲參數傳遞給Fortran例程,但最後''error_string''指針應該指向字符串。這與我如何從Python讀取 –

回答

2

這是一個可恥「解決方案「,根據您提供的設計來解決問題。

的main.c:

#include <stdio.h> 
#include <string.h> 

char error_string_[512]; 

void fortan_calculation_(double*, int*, int*); 

int main() { 
    double d = 2.5; 
    int l, i = 3; 
    memset(error_string_, 0, 512); 

    fortan_calculation_(&d, &i, &l); 
    error_string_[l] = 0; 
    printf("After call: '%s'\n", error_string_); 

} 

error.f90:

subroutine fortan_calculation(d, i, l) 
    implicit none 
    character(512) str 
    common /error_string/ str 
    double precision d 
    integer i, l 

    str = "Hello world!" 
    l = len_trim(str) 
end subroutine fortan_calculation 

編譯和測試:

$ gcc -c main.c 
$ gfortran -c error.f90 
$ gcc main.o error.o -lgfortran 
$ ./a.out 
After call: 'Hello world!' 

但這只是噁心代碼:它假設了很多(可以說)是Fortran編譯器的常見做法,而它存在一些使用iso_c_binding Fo正確鏈接C和Fortran的方法rtran模塊。

我來看看,看看我能不能拿出一個適當的解決方案。


編輯:實際上,有可用的nice SO page about that

+0

儘管它的醜陋,它確實是我想要的,謝謝!一個好處是沒有「交叉依賴性」。我沒有說的是,我也使用Fortran代碼作爲本地Fortran代碼的一部分。 –

4

你有兩個問題。一,如何從Fortran訪問C全局變量。這個比較簡單,用iso_c_binding在模塊中創建一個接口。一個例子見https://gcc.gnu.org/onlinedocs/gfortran/Interoperable-Global-Variables.html

但是,棘手的問題是,您已經將error_string定義爲指向char的指針。這意味着Fortran代碼在寫入之前必須先分配字符串。 Fortran可分配和指針變量與描述符一起工作,而不是原始指針,所以您必須首先創建一個到C malloc函數的接口。只有在此之後,你才能寫信給它。喜歡的東西:


module my_error_string 
    use iso_c_binding 
    interface 
    type(c_ptr) function c_malloc(size) bind(C, name="malloc") 
     use iso_c_binding 
     integer(kind=c_size_t), value :: size 
    end function c_malloc 
    end interface 
    type(c_ptr), bind(C) :: error_string 

contains 
    subroutine write_error(str) 
    character(len=*) :: str 
    character, pointer :: fstr(:) 
    integer(c_size_t) :: strlen 
    integer :: i 

    strlen = len(str, kind=c_size_t) + 1_c_size_t 
    error_string = c_malloc(strlen) 
    if (.not. c_associated(error_string)) then 
     call perror("error_string is a null pointer => malloc failed?!") 
     stop 1 
    end if 
    call c_f_pointer(error_string, fstr, shape=[strlen]) 
    do i = 1, len(str) 
     fstr(i) = str(i:i) 
    end do 
    fstr(strlen) = c_null_char 
    end subroutine write_error 
end module my_error_string 

(這可能是簡單的更改界面,使得你,而不是通過一個分配的C字符串的Fortran函數來填充,或者使用一個回調函數,但上面的作品,如果是這樣的。你想要什麼。)

+0

感謝您的解決方案!原則上這更優雅,但我認爲我會使用@Gilles的解決方案,因爲它會導致更簡單的Fortran代碼。這是一個實際的選擇,主要與我如何重用我的代碼的Fortran部分有關。 –

+0

@Tom:修正了現在實際運行的例子。但是,無論您想如何執行,跨C-Fortran邊界的字符串處理都很棘手。 – janneb