【问题标题】:What is the official way to deal with string in C++/FORTRAN interop在 C++/FORTRAN 互操作中处理字符串的官方方法是什么
【发布时间】:2017-05-31 15:52:09
【问题描述】:

我想了解 C++/FORTRAN 互操作性的最新改进,尤其是在字符串方面。以下是我不成功的尝试,请帮助我纠正或建议更好的解决方案。 我的编译器是 gcc 4.8.5

在 C++ 中

#include <iostream>

extern "C"{
    void SayHello(char*);
}
int main(int argc, char** argv){
    char * name = argv[1];
    SayHello(name);
    return 0;
}

在 Fortran 中

module MyModule

      contains
          subroutine SayHello(people) bind(c,name="SayHello")
              use, intrinsic :: iso_c_binding
              character, dimension(50), intent(in) :: people
              write(*,*) "Hello ", people
          end subroutine
end module MyModule

【问题讨论】:

  • 为什么您的尝试不成功?如果argv[1] 的长度至少不是 50,您肯定会遇到问题。也就是说,请显示任何错误或消息。
  • 由于我不知道为什么的原因(阅读:我在这里的原因),我收到以下编译错误,上面的代码是pastebin.com/Q4e48RkV
  • 我不熟悉 C++,但在我在答案中发布的 C 版本中,打印留给 Fortran 程序。你需要std::cout吗?
  • 哎呀,我会改正的

标签: c++ string fortran fortran-iso-c-binding


【解决方案1】:

尝试使用c_char 类型:

character(kind=c_char), dimension(*), intent(in)


编辑 1 因此,在@francescalus 提出问题后,我进一步研究了这一点。基本上,“假定大小”字符数组不是必需的1,尽管我确实相信 char 数组的大小是(如果我错了,请纠正我那)。我将在下面发布一个 C-calling-Fortran 版本,因为我不知道 C++ 语法,也不想查找它。


编辑 2 如脚注 1 所述,仅在 Fortran 程序中将 people 声明为假定大小的字符数组或(如 @VladimirF 所建议的)直接由 sz 给出的大小是正确的。我在下面的代码中清除了这一点。

Fortran 程序:

! SayHello.f90
subroutine SayHello(people,sz) bind(c,name="SayHello")
    use, intrinsic :: iso_c_binding
    implicit none
    ! Notes: 
    ! The size `sz` of the character array is passed in by value.
    ! Declare `people` as an assumed-size array for correctness, or just use the size `sz` passed in from C.
    character(kind=c_char), intent(in), dimension(sz) :: people
    integer(kind=c_int), intent(in), value :: sz
    write(*,*) "Hello, ", people(1:sz)
end subroutine

还有 C 程序:

/*Hello.c */    
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void SayHello(char *name, int len);

int main(int argc, char** argv){
    size_t sz = strlen(argv[1]);
    char * name = malloc(sz+1);
    strcpy(name, argv[1]);
    SayHello(name, sz+1);
    free(name);
    return 0;
}

编译(使用 ifort)、调用和输出:

ifort /c SayHello.f90 
icl Hello.c /link SayHello.obj
Hello.exe MattP
// output: Hello, MattP

1更新:似乎官方用法“用于互操作性”是声明为字符数组,使用假定大小:char(len=1,kind=c_char), dimension(*), intent(in)子>

【讨论】:

  • gfortran -c mymodule.f90 mymodule.f90:7.34: write(,) "Hello ", people 1 错误:最后一维的上限必须出现在在 (1) mymodule.f90:7.41: write(,) "Hello ", people 1 错误: (1) 处的数据传输元素不能是完整引用到一个假定大小的数组
  • @fanhako,虽然这个答案没有解决这个问题,但您应该知道people 是长度为 1 字符的假定大小数组,而不是假定长度字符的标量。使用假定大小的数组,您不能(正如编译器抱怨的那样)将它作为一个整体数组引用。你需要改变的不仅仅是一个声明。
  • 你能解释一下为什么显式形状数组的声明应该更改为假定大小的数组之一吗?
  • 您没有传递字符数组的大小(或字符标量的长度):character(kind=c_char), intent(in) :: people 是一个长度为 1 的标量字符,没有 dimension 语句。在这种情况下,people(1:sz) 是大于 1 的 sz 的无效子字符串引用(或标量的无效数组引用)。
  • 只需将正确的代码从注释移至真实代码即可。 character(kind=c_char), intent(in) :: people 是无效的,因为你会这样做 people(1:sz)character(kind=c_char), intent(in), dimension(*) :: people 甚至更好的character(kind=c_char), intent(in), dimension(sz) :: people 是必要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 2019-03-02
  • 2012-05-31
相关资源
最近更新 更多