[英]How do I pass a 2D array in C++ to a Fortran subroutine?
我正在编写一个小型的C ++程序,它将一个二维数组(复数)传递给一个Fortran子程序,然后将它接收回来填充值。 我写了一个通过并接收一维数组的版本,这很有效。 2-D版本不起作用(我的真正目标是编写具有大尺寸的4-D版本 - 因此必须动态分配这些数组)。
我将发布我的工作代码和非工作代码,但首先请注意我被迫使用结构(简单的,只包含两个双精度),因为Fortran似乎以与其自身的原始复数完全相同的方式解释它们。 这就是我的1-D版本有效的原因。 出于同样的原因,我不认为这是一个“复杂数字”的问题。
这是我的工作代码。 将一维复数数组传递给Fortran子程序:
Fortran子程序:
subroutine carray(A)
complex*16 A(2)
A(1) = cmplx(3,7)
A(2) = cmplx(9,5)
return
end
C ++代码:
include <iostream>
include <complex>
using namespace std;
struct cpx{double r, i;};
extern"C"
{
void carray_(struct cpx* A);
}
int main()
{
struct cpx* A;
A = new struct cpx [2];
carray_(A);
complex<double>* P;
P = new complex<double> [2];
for(x = 0; x < 2; x++)
{
real(P[x] = A[x].r;
imag(P[x] = A[x].i;
}
cout << real(P[0]) << "\t" << imag(P[0]) << "\n";
cout << real(P[1]) << "\t" << imag(P[1]) << "\n";
return 0;
}
使用以下命令进行编译无需投诉:
gfortran -c CarrayF.f
g++ -c CarrayC.cc
g++ -o Carray CarrayC.o CarrayF.o -lgfortran
因此,只要我将(本机)Fortran复数视为两个双精度的结构,我就可以将它们放入(非本机)C ++复杂类型中。 Fortran子程序似乎非常高兴收到一个指向它需要一个数组的指针。 到现在为止还挺好。
这是我传递2D数组的非工作尝试:
Fortran代码:
subroutine carray(A)
complex*16 A(2,2)
A(1,1) = cmplx(3,7)
A(1,2) = cmplx(9,5)
A(2,1) = cmplx(2,3)
A(2,2) = cmplx(4,9)
return
end
C ++代码:
include <iostream>
include <complex>
using namespace std;
struct cpx{double r, i;};
extern"C"
{
void carray_(struct cpx** A);
}
int main()
{
struct cpx** A;
A = new struct cpx* [2];
for(int x = 0; x < 2; x++)
{
A[x] = new struct cpx [2];
}
carray_(A);
complex<double>** P;
P = new complex<double>* [2];
for(int x = 0; x < 2; x++)
{
P[x] = new complex<double> [2];
}
for(x = 0; x < 2; x++)
{
for(int y = 0; y < 2; y++)
{
real(P[x][y] = A[x][y].r;
imag(P[x][y] = A[x][y].i;
}
}
cout << real(P[0][0]) << "\t" << imag(P[0][0]) << "\n";
cout << real(P[0][1]) << "\t" << imag(P[0][1]) << "\n";
cout << real(P[1][0]) << "\t" << imag(P[1][0]) << "\n";
cout << real(P[1][1]) << "\t" << imag(P[1][1]) << "\n";
return 0;
}
这实际上编译没有抱怨(与1-D版本相同的编译过程),但运行可执行文件会产生立即的分段错误。 由于一起使用两种语言的头痛,调试器没有帮助。
我在某个地方犯了一个小错误吗? 我似乎没有超出任何数组范围。 Fortran子程序很高兴收到一个指针,但显然它不知道如何处理指针指针。 通常,Fortran只会处理数组名称,即使是多维数组,但我需要了解Fortran如何处理2D数组。
在这个时代这样做的方法是使用ISO C绑定。 正式这是Fortran 2003的一部分,但得到了Fortran编译器的广泛支持,包括gfortran。 它甚至包括复杂类型的互操作性! 请参阅“内部模块”一章的“ISO_C_Binding”一节中的gfortran手册中的类型列表。 另外,“混合语言编程”一章中有几个例子。 在C ++方面,使用extern C来调用例程,以便在没有名称修改的情况下使用C调用约定。 在Fortran端,使用ISO C绑定。 然后,您将在语言级别具有兼容性,而不必对编译器的工作方式进行假设。
Fortran中的多维数组作为平面列主要数组存储在内存中。 它们不是指针的指针 - 它们实际上只是一维数组,你必须做一些额外的算术来计算数组索引。
从C ++传递数组的正确方法是这样的:
extern "C" void carray_(struct cpx *A);
...
struct cpx A[2*2];
carray_(A);
complex<double> P[2][2];
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
// note order of indicies: A is column-major
P[i][j] = std::complex<double>(A[j*2 + i].r, A[j*2 + i].i);
}
}
c ++中的二维数组不是 - 我重复不是 - 与指针{*}的指针相同!
当你这样做
struct cpx** A;
你正在建立一个所谓的“参差不齐的阵列”,而这个阵列没有相应的堡垒。 你想要的东西
struct cpx *A[2][2] = new struct cpx[2][2];
这是指向行2长的二维数组的指针。
{*}是的,您可以使用二维数组表示法访问指向指针的结构,但它们在内存中的布局不同。 :: grumble ::告诉其他人阵列和指针在c中是同一个东西需要遇到Big Foam Clue Bat的人。
<row-dimension>*<column-dimension>*sizeof(<type>)
的单个分配。 它的名称衰减为指向类型的指针。 <column-dimension<*sizeof(<type>*)
,另一个是<row-dimension>*sizeof(<type>)
。 这里要注意的是c ++和fortran相信数组在内存中的存储方式不同 。
C ++认为a[1][1]
之后的记忆位置是a[1][2]
,而fortran认为是a[2][1]
。 区别在于行主要(c,c ++等)和列主要(fortran,matlab,其他几个)。
请注意,默认情况下,这与fortran索引数组分开。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.