Fortran从C接受字符串(?)

vit*_*yav 4 c++ fortran

我觉得这应该是一个简单的问题,但我无法让它发挥作用.我有一些Fortran代码,它接受如下输入:

      SUBROUTINE TRACE(X,Y,NAME,XX,YY)
      EXTERNAL NAME
      CALL NAME(X,Y,XX,YY)
Run Code Online (Sandbox Code Playgroud)

我试图从以下形式传递C++的名称:

float x,y,xx,yy;
char * name="IGRF";
trace_(&x,&y,name,&xx,&yy);
Run Code Online (Sandbox Code Playgroud)

它编译,但当我尝试调用NAME子例程时,我总是得到段错误.在文件中定义了一个名为IGRF的子程序,我可以直接从C++调用IGRF子程序,但需要这个TRACE例程.在gdb中运行时,它表示NAME变量作为指向void的指针.

我已经尝试传递NAME,&NAME和NAME [0],一个字符名称[4],它被剥离了\ 0以完全符合名称,并且它们都返回显示相同的空指针.有谁知道如何从C++中将函数名称转换为Fortran中的EXTERNAL变量?

谢谢

Jon*_*rsi 12

因此,Fortran2003及更高版本的一个优点是C互操作性被定义为标准; 这是一个使用的PITA,但一旦完成,它可以保证跨平台和编译器工作.

所以这里cprogram.c,调用Fortran例程getstring:

#include <stdio.h>

int main(int argc, char **argv) {
    int l;
    char *name="IGRF";

    l = getstring(name);

    printf("In C: l = %d\n",l);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

而这里是fortranroutine.f90:

integer(kind=c_int) function getstring(instr) bind(C,name='getstring') 
    use, intrinsic :: iso_c_binding
    character(kind=c_char), dimension(*), intent(IN) :: instr
    integer :: len
    integer :: i

    len=0
    do
       if (instr(len+1) == C_NULL_CHAR) exit
       len = len + 1
    end do


    print *, 'In Fortran:'
    print *, 'Got string: ', (instr(i),i=1,len)
    getstring = len
end function getstring
Run Code Online (Sandbox Code Playgroud)

makefile很简单:

CC=gcc
FC=gfortran

cprogram: cprogram.o fortranroutine.o
    $(CC) -o cprogram cprogram.o fortranroutine.o -lgfortran

fortranroutine.o: fortranroutine.f90
    $(FC) -c $^

clean:
    rm -f *.o cprogram *~
Run Code Online (Sandbox Code Playgroud)

并且在gcc/gfortran和icc/ifort下运行它都有效:

 In Fortran:
 Got string: IGRF
In C: l = 4
Run Code Online (Sandbox Code Playgroud)

更新:哦,我刚刚意识到你正在做的事情比传递一个字符串更精细; 你本质上是试图传递一个指向C回调例程的函数指针.这是一个小问题,因为你必须使用Fortran interface来声明C例程 - 只使用extern将无法工作(并且不像显式接口那样好,因为没有类型检查等等)所以这应该工作:

cprogram.c:

#include <stdio.h>

/* fortran routine prototype*/
int getstring(char *name, int (*)(int));

int square(int i) {
    printf("In C called from Fortran:, ");
    printf("%d squared is %d!\n",i,i*i);
    return i*i;
}


int cube(int i) {
    printf("In C called from Fortran:, ");
    printf("%d cubed is %d!\n",i,i*i*i);
    return i*i*i;
}

int main(int argc, char **argv) {
    int l;
    char *name="IGRF";

    l = getstring(name, &square);
    printf("In C: l = %d\n",l);
    l = getstring(name, &cube);
    printf("In C: l = %d\n",l);


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

froutine.f90:

integer(kind=c_int) function getstring(str,func) bind(C,name='getstring')
    use, intrinsic :: iso_c_binding
    implicit none
    character(kind=c_char), dimension(*), intent(in) :: str
    type(c_funptr), value :: func

    integer :: length
    integer :: i

    ! prototype for the C function; take a c_int, return a c_int
    interface
        integer (kind=c_int) function croutine(inint) bind(C)
            use, intrinsic :: iso_c_binding
            implicit none
            integer(kind=c_int), value :: inint
        end function croutine
    end interface
    procedure(croutine), pointer :: cfun

    integer(kind=c_int) :: clen

    ! convert C to fortran procedure pointer,
    ! that matches the prototype called "croutine"
    call c_f_procpointer(func, cfun)

    ! find string length
    length=0
    do
       if (str(length+1) == C_NULL_CHAR) exit
       length = length + 1
    end do

    print *, 'In Fortran, got string: ', (str(i),i=1,length), '(',length,').'

    print *, 'In Fortran, calling C function and passing length'
    clen = length
    getstring = cfun(clen)

end function getstring
Run Code Online (Sandbox Code Playgroud)

结果如下:

$ gcc -g -Wall   -c -o cprogram.o cprogram.c
$ gfortran -c fortranroutine.f90 -g -Wall
$ gcc -o cprogram cprogram.o fortranroutine.o -lgfortran -g -Wall
$ gpc-f103n084-$ ./cprogram 
./cprogram 
 In Fortran, got string: IGRF(           4 ).
 In Fortran, calling C function and passing length
In C called from Fortran:, 4 squared is 16!
In C: l = 16
 In Fortran, got string: IGRF(           4 ).
 In Fortran, calling C function and passing length
In C called from Fortran:, 4 cubed is 64!
In C: l = 64
Run Code Online (Sandbox Code Playgroud)