[英]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.