2015-09-22 40 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