簡體   English   中英

將 Fortran 派生類型數組作為結構傳遞給 C function

[英]Passing Fortran derived type array to a C function as a struct

我有一個 Fortran 派生類型和一個匹配的 C 結構。 我正在創建派生類型的數組,我想將此數組傳遞給 C function。這是我的 Fortran 代碼

module tmod

use iso_c_binding

integer, parameter :: nstring = 22
integer, parameter :: ntype = 3
!! Type with a bind(c)
type, bind(c) :: mystruct
  character (c_char) :: hello (nstring)
  character (c_char) :: world (nstring)
  integer (c_int) :: ii
end type mystruct

interface !! Function on the C side
  integer (c_int) function testfunc (t, asize) bind(C, name="testfunc")
   use iso_c_binding
   import mystruct
    type (mystruct) :: t (:) !< array of struct/derived type
    integer (c_int), value :: asize !< Size of the array
  end function testfunc
end interface

end module tmod


program testprog

use tmod
use iso_c_binding

type(mystruct), target :: t (0:ntype-1) !< Array of derived type set up with C-like indicies
integer (c_int) :: i
!! Initialize the struct array
do j = 0,ntype-1
  t(j)%hello = "HelLo"//c_null_char
  t(j)%world = "World"//c_null_char
  t(j)%ii = j-3
enddo
!! Call C function
i = testfunc(t, ntype)
end program testprog

我的 C 代碼循環遍歷結構並打印 integer

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int const nstring = 22; /* matches string size from fortran */
struct mystruct{
  char hello[22];
  char world[22];
  int ii ;
}mystruct;

int testfunc (struct mystruct * t[], int asize ) {
/* Loop through array and print index then ii value */
  for (int j = 0; j < asize ; j++) {
          printf ("%d \n", j);
          printf ("%d \n", t[j]->ii);
  }
  return 0;
}

它們使用 icc 版本 2021.5.0 和 ifort 版本 2021.5.0 或 gcc 版本 11.2.0 進行編譯(這會刪除關於在此處為 mystruct t[] 聲明的注釋)。 它打印出第一個循環的結果。 它在第二次通過循環時給我一個分段錯誤。 我不能按值傳遞數組,因為它是一個數組,這顯然是不允許的。
如果我在沒有指針的情況下定義我的 C function

int testfunc (struct mystruct t[], int asize ) 

程序運行到最后,但沒有打印出正確的信息。 如何將這個 Fortran 數組傳遞給 C function?

您的 Fortran 接口有一個假設形狀的虛擬參數t 具有此假定形狀數組的testfunc接口不能與 C function 的形式參數struct mystruct * t[]互操作。可互操作的 C function 必須具有與指向CFI_cdesc_t 8828298954028 的指針關聯的參數

也就是說,在您顯示的代碼中沒有什么理由想要使用假定形狀的虛擬參數,因為您還傳遞了數組的大小。 而是使用顯式形狀參數:

interface !! Function on the C side
  integer (c_int) function testfunc (t, asize) bind(C, name="testfunc")
   use iso_c_binding
   import mystruct
    integer (c_int), value :: asize !< Size of the array
    type (mystruct) :: t (asize) !< array of struct/derived type
  end function testfunc
end interface

這將導致下一個問題:您不想要struct mystruct * t[]而是想要 struct struct mystruct *

int testfunc (struct mystruct *t, int asize ) {
/* Loop through array and print index then ii value */
  for (int j = 0; j < asize ; j++) {
          printf ("%d \n", j);
          printf ("%d \n", t[j].ii);
  }
  return 0;
}

或者,如果出於某種原因您確實需要 assumed-shape 參數:

interface !! Function on the C side
  integer (c_int) function testfunc (t) bind(C, name="testfunc")
   use iso_c_binding
   import mystruct
    type (mystruct) :: t (:) !< array of struct/derived type
  end function testfunc
end interface

你可以使它與互操作

int testfunc (CFI_cdesc_t* t) {
/* Loop through array and print index then ii value */
  struct mystruct *address;
  CFI_index_t subscript[1];
  for (int j = 0; j < t->dim[0].extent ; j++) {
    subscript[0] = j;
    printf ("%d \n", j);
    address = (struct mystruct *) CFI_address(t, subscript);
    printf ("%d \n", address->ii);
  }
  return 0;
}

無論哪種方式,你可能都想解決像這樣的任務

  t(j)%hello = "HelLo"//c_null_char

它將數組t(j)%hello設置為"H"的 22 個元素。 你會希望右側本身是一個包含 22 個元素的數組,比如:

  t(j)%hello = [character(c_char) :: "H", "e", "l", "L", "o", c_null_char, [(" ", i=1,16)]]

並且不要忘記自由地使用implicit none來減少意外的可能性。

暫無
暫無

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

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