簡體   English   中英

Fortran從C接受字符串(?)

[英]Fortran accepting string(?) from C

我覺得這應該是一個簡單的問題,但我無法讓它發揮作用。 我有一些Fortran代碼,它接受如下輸入:

      SUBROUTINE TRACE(X,Y,NAME,XX,YY)
      EXTERNAL NAME
      CALL NAME(X,Y,XX,YY)

我試圖從以下形式傳遞C ++的名稱:

float x,y,xx,yy;
char * name="IGRF";
trace_(&x,&y,name,&xx,&yy);

它編譯,但當我嘗試調用NAME子例程時,我總是得到段錯誤。 在文件中定義了一個名為IGRF的子程序,我可以直接從C ++調用IGRF子程序,但需要這個TRACE例程。 在gdb中運行時,它表示NAME變量作為指向void的指針。

我已經嘗試傳遞NAME,&NAME和NAME [0],一個字符名稱[4],它被剝離了\\ 0以完全符合名稱,並且它們都返回顯示相同的空指針。 有誰知道如何從C ++中將函數名稱轉換為Fortran中的EXTERNAL變量?

謝謝

因此,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;
}

這是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

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 *~

並且在gcc / gfortran和icc / ifort下運行它都有效:

 In Fortran:
 Got string: IGRF
In C: l = 4

更新 :哦,我剛剛意識到你正在做的事情比傳遞一個字符串更精細; 你本質上是試圖傳遞一個指向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;
}

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

結果如下:

$ 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

似乎FORTRAN 77需要指向字符的指針字符串的長度從C ++(或C)傳遞到FORTRAN。

請參閱這篇關於在FORTRAN中使用C和C ++的utah.edu文檔,並專門搜索以“CHARACTER * n arguments”開頭的文檔部分。

與支持表達式的反射和/或運行時評估的更動態語言(如python)相反,Fortran,C和C ++不支持。 也就是說,沒有內置方法將包含過程名稱的字符串轉換為過程引用並調用它。

也就是說,在您的示例中,NAME需要是指向函數的指針,而不是字符串。 通過使用ISO_C_BINDING功能,您可以在C和Fortran之間傳遞函數指針。

我也使用了CMake。

的CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(CppFortran C CXX Fortran)

add_executable(CppFortran
    froutine.f90
    main.cpp
    )

main.cpp中

#include <iostream>

extern "C" {
int getString(char *file_name);
}

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

    l = getString(name);
    std::cout << "In C++:"<< std::endl;
    std::cout << "length: " << l << std::endl;

    return 0;
}

froutine.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

控制台輸出:

 In Fortran:
 Got string: IGRF
In C++:
length: 4

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM