如何将C和Fortran中的字符串数组传递给Fortran? [英] How to pass arrays of strings from both C and Fortran to Fortran?

查看:528
本文介绍了如何将C和Fortran中的字符串数组传递给Fortran?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从C到Fortran子程序以及Fortran传递一组字符串到同一个Fortran子程序。我成功地从C和Fortran传递了单个字符串(即1D字符数组)。但是,我遇到了字符串数组的麻烦。我在Fortran方面使用ISO C绑定,理想情况下我希望在调用方面尽可能无缝。



我已阅读了一些相关问题和答案。有些(即这个)仅仅是使用ISO C而没有进一步的细节,这没有多大帮助。 此答案非常有用(类似于一个不同的问题),但只适用于单个字符串,其中似乎c_null_char在单个Fortran字符串中被识别。我不知道该如何处理数组的情况下没有两个单独的例程。

我现在有一个C例程,我想传递数组字符串(字符串):

  #include< iostream> 

externCvoid print_hi_array(char input_string [] [255]);

使用namespace std;

int main(){

char string [3] [255] = {asdf,ghji,zxcv};
print_hi_array(string);

返回0;
}

另外一个类似的Fortran例程:

 程序主
隐式无
调用print_hi_array((/asdf,ghji,zxcv/))
end program

到目前为止,这就是我在接收端的情况:

 子程序print_hi_array(input_string)bind(C)
仅使用iso_c_binding:C_CHAR,c_null_char

隐式无

字符(kind = c_char,len = 1),dimension(3,255),intent(in):: input_string
character(len = 255),dimension(3):: regular_string
字符(len = 255):: dummy_string
整数:: i,j,k

写入(*,*)input_string

do j = 1 ,3
dummy_string(:) = c_null_char
k = 1
do i = 1 +(j-1)* 255,j * 255,1
if(input_string(i) (*,*)i,i,j,input_string(i)
dummy_string(k:k)= input_string(i)
endif
k = k + 1
enddo
regular_string(j)= dummy_string
enddo

write(*,*)regular_string

子程序print_hi_array

这适用于C函数;我得到这个输出:

  asdfghjizxcv 
j = 1
i 1 1 a
i 2 1 s
i 3 1 d
i 4 1 f
j = 2
i 256 2 g
i 257 2 h
i 258 2 j
i 259 2 i
j = 3
i 511 3 z
i 512 3 x
i 513 3 c
i 514 3 v
asdf ghji zxcv



但是,当通过Fortran完成时,我得到了无稽之谈:

  asdfghjizxcv @ O,B @(P,B ] B] 6(P,B @ ....... 

在这种方法中似乎没有 c_null_char



那么,如何编写一个Fortran子例程来从C和Fortran中接收字符串数组?

解决方案

Fortran使用空格填充字符串的其余部分(如果声明的时间比存储的文本长)。它不是零分隔的,声明的长度存储在一个隐藏的变量中。它不包含c空字符,因此你正在阅读一些垃圾(缓冲区溢出)。什么Fortran应该打印时打印一个字符串\000是未定义的标准,并取决于实施。



特别是,你也传递一个字符(4 )维数为3的数组添加到需要更多数据的子例程(255个字符,尽管我对索引顺序不太确定)。只有指针被传递,所以我认为它不能被检查。

可以通过这种方式在数组构造函数中定义字符串的长度:

  [字符(255)::a,ab,abc] 


I am trying to pass an array of strings from C to a Fortran subroutine as well as from Fortran to that same Fortran subroutine. I have managed to pass single strings (i.e. 1D character arrays) successfully from both C and Fortran. However, I'm having trouble with arrays of strings. I am using ISO C binding on the Fortran side, and ideally I'd like this to be as seamless as possible on the calling side.

I have read some related questions and answers. Some, (i.e. this and this) are simply "Use ISO C" without further details, which doesn't help much. This answer was very helpful (similar answer to a different question), but only works for single strings, where it seems that the c_null_char is recognized in the single Fortran string. I can't figure out what to do for the array case without having two separate routines.

What I currently have is a C routine which I want to pass the array of strings (string) from:

#include <iostream>

extern "C" void print_hi_array(char input_string[][255]);

using namespace std;

int main() {

  char string[3][255] = {"asdf","ghji","zxcv"};   
  print_hi_array(string);

  return 0;
}

And, a similar Fortran routine:

program main
  implicit none
  call print_hi_array( (/"asdf", "ghji", "zxcv"/) )
end program

Thus far, this is what I have for the receiving end:

subroutine print_hi_array(input_string) bind(C)
  use iso_c_binding, only: C_CHAR, c_null_char

  implicit none

  character (kind=c_char, len=1), dimension (3,255), intent (in) :: input_string
  character (len=255), dimension (3) :: regular_string
  character (len=255) :: dummy_string
  integer :: i,j,k

  write (*,*) input_string

  do j = 1 , 3
    dummy_string(:) = c_null_char
    k = 1
    do i = 1 + (j-1)*255, j*255,1
      if (input_string(i) .ne.  c_null_char) then
        write (*,*) "i ",i,j, input_string(i)
        dummy_string(k:k) = input_string(i)
      endif
    k = k +1
    enddo
    regular_string(j) = dummy_string
  enddo

  write (*,*) regular_string

end subroutine print_hi_array

This works for the C function; I get this output:

 asdfghjizxcv
 j=           1
 i            1           1 a
 i            2           1 s
 i            3           1 d
 i            4           1 f
 j=           2
 i          256           2 g
 i          257           2 h
 i          258           2 j
 i          259           2 i
 j=           3
 i          511           3 z
 i          512           3 x
 i          513           3 c
 i          514           3 v
 asdf   ghji   zxcv   

However, when it's done through Fortran I get nonsense out:

asdfghjizxcv@O,B�@(P,B�]B]6(P,B�@ .......

It seems there is no c_null_char in this approach.

So, how can I write a Fortran subroutine to take in arrays of strings from both C and Fortran?

解决方案

Fortran uses spaces to fill the rest of the string if it is declared longer than its stored text. It is not zero delimited, the declared length is stored in a hidden variable. It does not contain c null char and therefore you are reading some garbage (buffer overflow). What Fortran should print when tlit prints a string with \000 is undefined by the standard and depends on the implementation.

In particular, you are also passing a character(4) array with dimension 3 to a subroutine that expects much more data (255 chars, though I am not shure about the index order). Only pointers are passed so I think it can not be checked.

It is possible to define the length of the strings in the array constructor this way:

[character(255) :: "a","ab","abc"]

这篇关于如何将C和Fortran中的字符串数组传递给Fortran?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆