当我将一个指针从 Fortran 传递给 C++ 时,第一个元素的值丢失了
When I pass a pointer from Fortran to C++ the value of the first element is lost
我正在从 C++ 调用 Fortran 函数,它分配一个向量,然后它 returns 从 C++ 到该向量的指针。问题是,当我使用此指针在 C++ 中打印值时,向量第一个元素的值丢失了。我不确定我是否做错了。
以下是我的C++代码:
#include <iostream>
#include <cstdio>
using namespace std;
extern"C" {
void fortfunc_(int *ii, void *ff);
}
main()
{
int ii=5;
double *ff;
int i;
// Calling my Fortran function:
fortfunc_(&ii, &ff);
printf("#C++ address: %p\n", ff);
for (i=0; i<ii; i++)
printf(" ff[%3d] = %f\n",i,ff[i]);
return 0;
}
我的 Fortran 代码:
subroutine fortfunc(ii,ffp)
use, intrinsic :: iso_c_binding
integer(kind=4), intent(in) :: ii
type(C_PTR), intent(out) :: ffp
real(kind=8), dimension(:), allocatable, target :: ff
integer(kind=4) :: err, i
!Allocating memory for ff:
allocate(ff(ii),stat=err)
print *,'allocate returned: ',err
ffp = C_LOC(ff(1))
write(*,'(a,z20)') '#Fortran address:', C_LOC(ff(1))
do i=1,ii
ff(i) = i
end do
print*,"Writing some vectors:"
print*,"ii = ",ii
print*,"ff= ",ff
return
end
如果我运行它我得到以下输出:
allocate returned: 0
#Fortran address: 3B5AE0
Writing some vectors:
ii = 5
ff= 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000
#C++ address: 003B5AE0
ff[ 0] = 0.000000
ff[ 1] = 2.000000
ff[ 2] = 3.000000
ff[ 3] = 4.000000
ff[ 4] = 5.000000
如你所见,ff[0] = 0 且必须为 1。
如果您引用 ISO_C_BINDING 内部模块,那么您的 Fortran 编译器几乎肯定支持 C 互操作 Fortran 过程和接口的 BIND(C) 后缀。将后缀 BIND(C, NAME='what_you_want_the_thing_called_in_C")
放在子例程语句上,并避免围绕 Fortran 过程的符号名称的所有与处理器相关的愚蠢行为。这也确保参数以 C 互操作的方式传递。
Fortran 子例程中的变量 ff
是一个本地的、未保存的可分配变量。从 Fortran 95 开始,当子程序完成执行时,它会自动释放。该对象的第一个元素的 C 地址在那时变得无效 - 因此在 C 代码中你试图取消引用一个无效的指针(它指向不再分配的内存)。
您需要考虑一些管理 Fortran ff
变量生命周期的方法。一种方法是使它成为 Fortran 指针,并提供一个单独的 Fortran 例程来指示何时可以释放该指针。
我正在从 C++ 调用 Fortran 函数,它分配一个向量,然后它 returns 从 C++ 到该向量的指针。问题是,当我使用此指针在 C++ 中打印值时,向量第一个元素的值丢失了。我不确定我是否做错了。
以下是我的C++代码:
#include <iostream>
#include <cstdio>
using namespace std;
extern"C" {
void fortfunc_(int *ii, void *ff);
}
main()
{
int ii=5;
double *ff;
int i;
// Calling my Fortran function:
fortfunc_(&ii, &ff);
printf("#C++ address: %p\n", ff);
for (i=0; i<ii; i++)
printf(" ff[%3d] = %f\n",i,ff[i]);
return 0;
}
我的 Fortran 代码:
subroutine fortfunc(ii,ffp)
use, intrinsic :: iso_c_binding
integer(kind=4), intent(in) :: ii
type(C_PTR), intent(out) :: ffp
real(kind=8), dimension(:), allocatable, target :: ff
integer(kind=4) :: err, i
!Allocating memory for ff:
allocate(ff(ii),stat=err)
print *,'allocate returned: ',err
ffp = C_LOC(ff(1))
write(*,'(a,z20)') '#Fortran address:', C_LOC(ff(1))
do i=1,ii
ff(i) = i
end do
print*,"Writing some vectors:"
print*,"ii = ",ii
print*,"ff= ",ff
return
end
如果我运行它我得到以下输出:
allocate returned: 0
#Fortran address: 3B5AE0
Writing some vectors:
ii = 5
ff= 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000
#C++ address: 003B5AE0
ff[ 0] = 0.000000
ff[ 1] = 2.000000
ff[ 2] = 3.000000
ff[ 3] = 4.000000
ff[ 4] = 5.000000
如你所见,ff[0] = 0 且必须为 1。
如果您引用 ISO_C_BINDING 内部模块,那么您的 Fortran 编译器几乎肯定支持 C 互操作 Fortran 过程和接口的 BIND(C) 后缀。将后缀 BIND(C, NAME='what_you_want_the_thing_called_in_C")
放在子例程语句上,并避免围绕 Fortran 过程的符号名称的所有与处理器相关的愚蠢行为。这也确保参数以 C 互操作的方式传递。
Fortran 子例程中的变量 ff
是一个本地的、未保存的可分配变量。从 Fortran 95 开始,当子程序完成执行时,它会自动释放。该对象的第一个元素的 C 地址在那时变得无效 - 因此在 C 代码中你试图取消引用一个无效的指针(它指向不再分配的内存)。
您需要考虑一些管理 Fortran ff
变量生命周期的方法。一种方法是使它成为 Fortran 指针,并提供一个单独的 Fortran 例程来指示何时可以释放该指针。