【问题标题】:fortran pass character*81 array to c/c++ codefortran 将字符*81 数组传递给 c/c++ 代码
【发布时间】:2015-05-24 03:10:09
【问题描述】:

我是编程新手,我想在我的 c++ 代码中调用一个 fortran 函数。问题是我不知道如何将 fortran character*81 数组传递给我的 c++。

fortran 代码如下:

subroutine func01(a)
    implicit none
    character*81 a(2)
    write(*,*) a(1)
    write(*,*) a(2)
end

c++代码是这样的:

#include <iostream>

extern "C"{
    void func01_( const char **a );
}    

int main()
{
    const char *a[2];
    a[0]="Hello world!";
    a[1]="This is a test!";
    func01_(a);
    return 0;
}

我用这个基本测试了我的fortran代码

program pro01
    character*81 a(2)
    a(1)='Hello world!'
    a(2)='This is a test!'
    call func01(a)
end program pro01

'func01(a)' 效果很好。

感谢@PaulMcKenzie,我纠正了一些愚蠢的问题.....

但是,当我编译 cpp 代码时,结果就像乱七八糟的代码:

 7
@L
@��n��@�UH�j��FP
 @��n���U�շ�=��U�ྼ���   @��

我该怎么办?

【问题讨论】:

  • 我认为你需要复习基本的 C++:char a[2][81]; a[0][81]="Hello world!"; 这不是用字符串初始化 char 数组的方法。 C++ 不是 Fortran。
  • 您使用的是哪个工具链?从布局上看,显然不是F77。直到 Fortran 95,没有内置的 C 互操作性,任何接口都是特定于供应商的。从 Fortran 2003 开始​​,C(不是 C++)互操作性。
  • 谢谢@cup ...但是,我没有抓住你.....我所做的是:第1步。 gfortran -ffree-form -c func01.f ;第2步。 g++ -std=c++0x -c tstcpp.cpp ;第三步。 g++ -o tst01 func01.o tstcpp.o;就是这样......
  • 在 Internet 上搜索 ISO_C_BINDING。您将获得很多成功,并且可能会解决您的问题。

标签: c++ fortran fortran77 mixing


【解决方案1】:

以下代码似乎适用于 Linux(x86_64) 上的 gcc4,但不清楚它是否也适用于其他平台。 (如上所述,现代 Fortran 的 C 互操作性可能很有用。)

func01.f90

subroutine func01( a )
    character(*) :: a( 2 )
    print *
    print *, "char length = ", len(a(1)), len(a(2))
    print *, "raw a(1) : [", a(1), "]"
    print *, "raw a(2) : [", a(2), "]"
    print *, "trim     : [", trim(a(1)), "] [", trim(a(2)), "]"
end

main.cpp

extern "C" {
    void func01_( char *c, const int len );
}

#include <iostream>
#include <cstring>  // for memset()
int main()
{
    const int lenmax = 30, numstr = 3; // changed char length to 30 to fit in the terminal
    char a[ numstr ][ lenmax ];
    std::string str[ numstr ];

    str[0] = "moon"; str[1] = "mercury"; str[2] = "jupiter";

    for( int k = 0; k < numstr; k++ ) {
        memset( a[k], ' ', lenmax );  // fill space                                              
        str[k].copy( a[k], lenmax );  // copy at most lenmax char (no \0 attached)                        
    }

    func01_( a[0], lenmax );
    func01_( a[1], lenmax ); // pass from mercury
    return 0;
}

编译

$ g++ func01.f90 main.cpp -lgfortran

结果

char length =           30          30
raw a(1) : [moon                          ]
raw a(2) : [mercury                       ]
trim     : [moon] [mercury]

char length =           30          30
raw a(1) : [mercury                       ]
raw a(2) : [jupiter                       ]
trim     : [mercury] [jupiter]

【讨论】:

  • 我认为字符串作为char* 传递,它们的长度作为“隐藏”变量附加在参数列表的末尾。但这可能是系统特定的(例如,当存在多个 character 参数时),所以请检查更便携的方式...
  • 谢谢@roygvib,我觉得你的回答对我来说已经足够了,非常感谢。
【解决方案2】:

这是一个可移植的解决方案,用于将任意长度的字符串数组从 C 传递到 Fortran。

我使用的 C++ 文件与您的文件非常相似:

#include <iostream>

extern "C" void func01(const char **a);

int main()
{
  const char *a[2] = {"Hello World","This is a test"};
  func01(a);
  return 0;
}

上面唯一的变化是字符数组的初始化和删除 Fortran 函数的不那么便携的下划线。相反,我们将使用 Fortran 2003 提供的标准 C 互操作性。func01 的 Fortran 实现变为:

subroutine func01(cstrings) bind(C,name="func01")
  use, intrinsic :: iso_c_binding, only: c_ptr, c_char, c_f_pointer
  implicit none
  type(c_ptr), dimension(2), target, intent(in) :: cstrings
  character(kind=c_char), pointer :: a1(:), a2(:)

  ! size_t strlen(char * s);
  interface
     function strlen(s) bind(C, name='strlen')
       use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t
       implicit none
       type(c_ptr), intent(in), value :: s
       integer(c_size_t) :: strlen
     end function strlen
  end interface

  call c_f_pointer(cstrings(1), a1, [strlen(cstrings(1))])
  call c_f_pointer(cstrings(2), a2, [strlen(cstrings(2))])
  write (*,*) a1
  write (*,*) a2
end subroutine func01

bind 属性使我们能够与 C 的函数名称互操作,并且我们使用 C 类型的变量。变量 cstrings 将采用 2 个指针的数组,或者在 C 中,*[2]**。该过程的大部分是一个接口块,它允许我们调用标准 C 库例程 strlen 以使我们的生活更轻松,并通过以下对 c_f_pointer 的调用将 C 指针转换为 Fortran 指针。

编译并运行时,如预期的那样,输出是:

$ ./string-array-test
 Hello World
 This is a test

使用 gcc 5.1.0 编译和测试。

【讨论】:

  • 好人!非常感谢! @凯西;就像cup所说的那样,这是一种iso_c_binding,bcs,我搜索了iso_c_binding,许多fortran代码都有“bind(C,name =“func01”)之类的东西。再一次非常感谢你!干杯..
  • @Kylxyz 是的,这是现代 Fortran iso_c_binding(如在上述代码中使用该模块所指出的那样)
猜你喜欢
  • 1970-01-01
  • 2014-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多