代码之家  ›  专栏  ›  技术社区  ›  M.E.

如何在Fortran中将NULL字符连接到字符数组以调用c函数?

  •  1
  • M.E.  · 技术社区  · 3 年前

    我有以下测试功能:

    #include <stdlib.h>
    #include <stdio.h>
    
    void print_string(char *text);
    
    void print_string(char *text) {
        printf("---\n%s\n---\n", text);
    }
    

    以下模块使用iso c绑定将调用封装为Fortran子例程:

    module test_c_lib
    
            use iso_c_binding
            implicit none
                    
    contains
            
        subroutine test(text)
        
                use iso_c_binding
                
                character,intent(in)       :: text(:)
                
                ! Interface to C function
                interface
                        subroutine c_print_string(t) bind(C, name="print_string")
                                import
                                character(kind=c_char) :: t(:)
                        end subroutine
                end interface
                
                ! Call C function
                print *,"AAAAA"
                print *,text
                print *,"AAAAA"         
                
                call c_print_string(text // C_NULL_CHAR)
                
        end subroutine
        
    end module
    

    使用ISO C BINDINGS在Fortran中定义子例程的方法摘录自以下文档 link 。我进一步将其封装为 f2py 不支持iso c绑定。

    我通过编译所有内容 makefile :

    $ cat makefile 
    f_mod.so:       f_mod.f90 c_lib.o
                    f2py -c f_mod.f90 c_lib.o -m f_mod
    
    c_lib.o:        c_lib.c
                    gcc -c -fpic c_lib.c -o c_lib.o
    

    它编译但:

    1. 我收到以下警告:
          150 |                 call c_print_string(text // C_NULL_CHAR)
              |                                    1
        Warning: Character length mismatch (2/1) between actual argument and assumed-shape dummy argument 't' at (1) [-Wargument-mismatch]
    
    1. 当通过调用时,我得到以下输出 import fmod; f_mod.test_c_lib.test("Foo") :
         AAAAA
         Foo
         AAAAA
        ---
        8v$
        ---
    

    所以 f2py 正在工作,但经过时 text // C_NULL_CHAR 作为参数,它似乎不起作用,因为我从C函数输出中得到了垃圾。

    0 回复  |  直到 3 年前
        1
  •  2
  •   francescalus    3 年前

    您有两个错误:

    要使字符伪参数与 char * C参数, t 应该是 assumed size array :

    character(kind=c_char) :: t(*)   ! Assumed size, not assumed shape
    

    您也可以使用 CFI_cdesc_t C型 t 一个假定形状的数组,或者一个假定长度的标量,但这要高级得多。

    甚至制造 t 假设大小,您没有工作程序,因为下一个问题:的基本性质 // .

    text 是一个(假定形状)数组连接 text // C_NULL_CHAR 元素化完成,给出长度为2的数组 1. 的每个元素 文本 与C null字符连接。然后,C函数看到的输入看起来像 [text(1), C_NULL_CHAR, text(2), C_NULL_CHAR, ...] .

    具有长度为1的字符数组 C_NULL_CHAR 附加,则需要使用数组构造函数:

    call c_print_string([text,C_NULL_CHAR])
    

    1. 该参数的长度为2,这是关于“字符长度不匹配”的警告的原因。

        2
  •  0
  •   Scientist    3 年前

    @弗朗西斯的回答是正确的。但由于我在看到他的答案之前就解决了这个问题,我在这里发布了完整的功能代码:

    module test_c_lib
    
            use iso_c_binding
            implicit none
    
    contains
    
        subroutine test(text)
    
            use iso_c_binding
    
            character(*),intent(in) :: text
    
            ! Interface to C function
            interface
                    subroutine c_print_string(t) bind(C, name="print_string")
                            import
                            character(kind=c_char) :: t(*)
                    end subroutine
            end interface
    
            ! Call C function
            print *,"Inside Fortran"
            print *,text
            print *,"Inside Fortran"
    
            call c_print_string(text // C_NULL_CHAR)
    
        end subroutine
    
    end module test_c_lib
    
    program test_prog
        use test_c_lib
        call test(text = "Hello C World")
    end program test_prog
    

    注意对的接口所做的更改 subroutine test(text) 和C功能接口 print_string() .通过以下命令编译代码,

    icl print_string.c -c
    ifort test_c_lib.f90 -c
    ifort *.obj /exe:main.exe
    

    text // C_NULL_CHAR [text,C_NULL_CHAR] 当然 ifort 不需要它。以下是输出:

    > main.exe
     Inside Fortran
     Hello C World
     Inside Fortran
    ---
    Hello C World
    ---