[英]C to Fotran: Interoperability of a C pointer to a char array, declared in a struct
I am creating Fortran bindings to a C library.我正在创建到 C 库的 Fortran 绑定。 The C header defines a
struct
as follows: C 头文件定义了一个
struct
,如下所示:
struct frame {
char *foo[4];
int bar;
};
(in reality, the C struct is much more complicated, I just stripped it down to the essential part). (实际上,C 结构体要复杂得多,我只是将其分解为基本部分)。 Now, the C library also provides a function that gives values to the struct.
现在,C 库还提供了一个为结构体赋值的函数。 For the purposes of this question, I wrote a simplified replacement of such a function:
出于这个问题的目的,我写了一个对这样一个函数的简化替换:
void setFrame(struct frame *fr) {
fr->bar=12;
printf("bar in C: %d\n", fr->bar);
}
(I don't really care about the value of foo
, but I do care about the value of bar
, and I won't get it correctly on the Fortran side if foo
isn't declared properly). (我并不真正关心
foo
的值,但我确实关心bar
的值,如果foo
未正确声明,我将无法在 Fortran 端正确获取它)。 Now, this is my Fortran implementation of the above:现在,这是我对上述内容的 Fortran 实现:
module binding
use iso_c_binding
implicit none
private
type, bind(c), public :: frame
integer(kind=c_int), dimension(4) :: foo
integer(kind=c_int) :: bar
end type Frame
public :: setFrame
interface
subroutine setFrame_C(fr) bind(c, name="setFrame")
import :: c_ptr
type(c_ptr), value :: fr
end subroutine setFrame_C
end interface
contains
subroutine setFrame(fr)
type(frame), intent(inout), target :: fr
call setFrame_C(c_loc(fr))
end subroutine setFrame
end module binding
and this is a test Fortran program:这是一个测试 Fortran 程序:
program test
use binding
implicit none
type(frame) :: fr
print "(a,i0)","bar in Fortran (before calling setFrame): ",fr%bar
call setFrame(fr)
print "(a,i0)","bar in Fortran (after calling setFrame): ",fr%bar
end program test
Running the above program gives:运行上面的程序给出:
bar in Fortran (before calling setFrame): -1076110840
bar in C: 12
bar in Fortran (after calling setFrame): 12
meaning the Fortran binding works.意味着 Fortran 绑定有效。 Note that the equivalent of
char *foo[4]
is an integer array of c_int
.请注意,
char *foo[4]
的等价物是c_int
的整数数组。 This is a bit surprising because, although there is not much of a difference between a C integer and a C char, I would expect C char to be a one-byte integer.这有点令人惊讶,因为虽然 C 整数和 C char 之间没有太大区别,但我希望 C char 是一个单字节整数。 Now, if I declare
char *foo[4]
in a more "natural" way:现在,如果我以更“自然”的方式声明
char *foo[4]
:
character(kind=c_char), dimension(4) :: foo
it doesn't work (I don't get the correct value for fr.bar
).它不起作用(我没有得到
fr.bar
的正确值)。 The reason is that, at least in gfortran 11.2.0, c_int
is actually equal to 4 while c_char
is equal to 1. Even character(kind=c_int)
works.原因是,至少在 gfortran 11.2.0 中,
c_int
实际上等于 4 而c_char
等于 1。甚至character(kind=c_int)
工作。 I fact, character(kind=4)
also works, although the compiler (correctly) issues a warning in this case.事实上,
character(kind=4)
也可以工作,尽管在这种情况下编译器(正确地)发出警告。
So my question is... what is actually the correct, "formal" way to treat char *foo[4]
on the Fortran side, portable to another compiler that probably treats C char in another way?所以我的问题是......在 Fortran 端处理
char *foo[4]
真正正确的“正式”方式是什么,可移植到另一个可能以另一种方式处理 C char 的编译器?
The problem is that char *foo[4];
问题是
char *foo[4];
is an array of four pointers to char, so your interoperable declaration in Fortran has to be是一个由四个指向 char 的指针组成的数组,因此您在 Fortran 中的可互操作声明必须是
type, bind(c), public :: frame
type(c_ptr), dimension(4) :: foo
integer(kind=c_int) :: bar
end type Frame
Your way only happens to work because you are probably testing on a 32bit platform where a pointer has the same width as an int.您的方法只是碰巧有效,因为您可能正在 32 位平台上进行测试,其中指针与 int 具有相同的宽度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.