在 C++ 中调用 fortran 子例程时出现分段错误
segmentation fault when calling fortran subroutine in C++
我正在尝试调用 C++ 中的 Fortran 子例程。
这是子程序的开始:
subroutine fireballess(ear,ne,parames,ifl,photar,photer)
integer ne,ifl
real*4 ear(0:ne),parames(10),photar(ne),photer(ne)
该子例程在 Fortran 中运行良好,但当我尝试在 C++ 中调用它时出现分段错误。这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C" void fireballess_( double *fear, int fne,double* fparames, nt fifl, double *fphotar, double *fphoter);
int main(int argc, char ** argv)
{
int ne,ifl;
double *ear;
double *parames;
double *photar;
double *photer;
parames = new double[9];
parames[0]=4.3;
parames[1]=0.23;
parames[2]=0.5;
parames[3]=0.5;
parames[4]=1.5;
parames[5]=1.;
parames[6]=1000.;
parames[7]=2.15;
parames[8]=3.;
ne = 3;
ear = new double[ne];
ear[0] = 0.;
ear[1] = 20.;
ear[2] = 40.;
ifl=2;
photar = new double[ne];
photer = new double[ne];
// Check on variables initialization
for (int i=0;i<=2;i++) cout << ear[i] <<",";
cout <<" "<< ne<<" ";
for (int i=0;i<=8;i++) cout << parames[i] <<",";
cout <<" "<< ifl <<" "<< photar[0] <<" "<< photer[0] << endl;
cout << "Calling a Fortran subroutine" << endl;
cout << "===============================" << endl;
// call to the subroutine -->segmentation fault
fireballess_(ear,ne,parames,ifl,photar,photer);
for (int i=0;i<=ne;i++){
cout << "ear = " <<ear[i-1]<< " - "<<ear[i] << endl;
cout << "photar = " << photar[i] << endl;
cout << "photer = " << photer[i] << endl << endl;
}
delete[] ear;
delete[] parames;
delete[] photar;
delete[] photer;
}
程序在调用子例程时崩溃。我在 C++ 或 Fortran 编码方面不是很有经验,所以我不确定该怎么做。到目前为止,我已经检查了传递给子程序的变量的格式是否正确,看起来是这样。
提前感谢您的帮助
------------编辑------
阅读一些评论后我修改了代码如下,调用例程时仍然出现相同的分段错误:
using namespace std;
extern "C" void fireballess_( std::vector<float> fear, int fne,std::vector<float> fparames, int fifl, std::vector<float> fphotar, std::vector<float> fphoter);
int main(int argc, char ** argv)
{
int ne,ifl;
ifl=2;
ne = 3;
std::vector<float> parames = {4.3,0.23,0.5,0.5,1.5,1.,1000.,2.15,3.};
std::vector<float> ear={0,20,40};
std::vector<float> photar;
std::vector<float> photer;
cout << "Calling a Fortran subroutine" << endl;
cout << "===============================" << endl;
fireballess_(ear,ne,parames,ifl,photar,photer);
for (int i=0;i<ne;i++){
cout << "ear = " <<ear[i-1]<< " - "<<ear[i] << endl;
cout << "photar = " << photar[i] << endl;
cout << "photer = " << photer[i] << endl << endl;
}
}
从 C 和 C++ 代码调用 Fortran 函数的现代方法是通过 ISO_C_BINDING
,请参见其 tag wiki on SO。没有这个界面会有一些怪癖,比如
- 所有变量都通过引用(指针)传递给 Fortran 函数
- 传递数组时还必须传递它们的长度
- ...
这种古怪的 C/Fortran 互操作方式被描述为例如here.
请注意,您不能将 std::vector
或任何其他复杂的 C++ 对象传递给 C 或 Fortran 函数并期望它会理解它。这很可能不起作用,除非该功能旨在处理此问题。因此,您需要从这些对象中获取实际的 low-level 数据(例如指向数组的指针)并传递它们。
结合评论和其他答案中的各种信息,我猜原始代码的 minimum-modified 版本可能如下所示:
fortsub.f90
subroutine fireballess(ear, ne, parames, ifl, photar, photer)
implicit none
integer ne, ifl
real*4 ear(0:ne), parames(10), photar(ne), photer(ne)
print *, "ear = ", ear
print *, "ne = ", ne
print *, "parames = ", parames
print *, "ifl = ", ifl
print *, "photar = ", photar
print *, "photer = ", photer
print *
print *, "sizeof(integer) = ", sizeof(ne)
print *, "sizeof(real*4) = ", sizeof(ear(1))
end
main.cpp
#include <iostream>
extern "C"
void fireballess_( float *ear, int *ne, float *parames,
int *ifl, float *photar, float *photer );
int main()
{
std::cout << "sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "sizeof(float) = " << sizeof(float) << std::endl;
int ne = 3, ifl = 2;
float *ear = new float[ne + 1] { 0.0f, 20.0f, 40.0f, 60.0f };
float *parames = new float[10]
{ 0.1f, 0.2f, 0.3f, 0.4f, 0.5f,
0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
float *photar = new float[ne] { 1.0f, 2.0f, 3.0f };
float *photer = new float[ne] { 4.0f, 5.0f, 6.0f };
fireballess_( ear, &ne, parames, &ifl, photar, photer );
delete[] ear;
delete[] parames;
delete[] photar;
delete[] photer;
}
这里修改的部分是: (1) Fortran中的real*4
通常对应C++中的float
; (2) 我们需要传递实际参数的地址(特别是 ne
和 ifl
); (3) ear
应该有 ne + 1
元素,因为它在 Fortran 端被定义为 ear(0:ne)
。然后,将代码编译为
$ gfortran-8 -c fortsub.f90
$ g++-8 main.cpp fortsub.o -lgfortran
给出(使用 GCC8 + MacOS10.13)
sizeof(int) = 4
sizeof(float) = 4
ear = 0.00000000 20.0000000 40.0000000 60.0000000
ne = 3
parames = 0.100000001 0.200000003 0.300000012 0.400000006 0.500000000 0.600000024 0.699999988 0.800000012 0.899999976 1.00000000
ifl = 2
photar = 1.00000000 2.00000000 3.00000000
photer = 4.00000000 5.00000000 6.00000000
sizeof(integer) = 4
sizeof(real*4) = 4
如果我们使用std::vector
,对应的代码可能是这样的(通过查看std::vector
上的一些教程...)
// main2.cpp
#include <iostream>
#include <vector>
extern "C"
void fireballess_( float *ear, int *ne, float *parames,
int *ifl, float *photar, float *photer );
using Vecf = std::vector<float>;
int main()
{
int ne = 3, ifl = 2;
Vecf ear { 0.0f, 20.0f, 40.0f, 60.0f };
Vecf parames { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f,
0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
Vecf photar { 1.0f, 2.0f, 3.0f };
Vecf photer { 4.0f, 5.0f, 6.0f };
fireballess_( ear.data(), &ne, parames.data(),
&ifl, photar.data(), photer.data() );
}
这似乎给出了相同的结果(通过将 main.cpp
替换为 main2.cpp
)。
我正在尝试调用 C++ 中的 Fortran 子例程。
这是子程序的开始:
subroutine fireballess(ear,ne,parames,ifl,photar,photer)
integer ne,ifl
real*4 ear(0:ne),parames(10),photar(ne),photer(ne)
该子例程在 Fortran 中运行良好,但当我尝试在 C++ 中调用它时出现分段错误。这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C" void fireballess_( double *fear, int fne,double* fparames, nt fifl, double *fphotar, double *fphoter);
int main(int argc, char ** argv)
{
int ne,ifl;
double *ear;
double *parames;
double *photar;
double *photer;
parames = new double[9];
parames[0]=4.3;
parames[1]=0.23;
parames[2]=0.5;
parames[3]=0.5;
parames[4]=1.5;
parames[5]=1.;
parames[6]=1000.;
parames[7]=2.15;
parames[8]=3.;
ne = 3;
ear = new double[ne];
ear[0] = 0.;
ear[1] = 20.;
ear[2] = 40.;
ifl=2;
photar = new double[ne];
photer = new double[ne];
// Check on variables initialization
for (int i=0;i<=2;i++) cout << ear[i] <<",";
cout <<" "<< ne<<" ";
for (int i=0;i<=8;i++) cout << parames[i] <<",";
cout <<" "<< ifl <<" "<< photar[0] <<" "<< photer[0] << endl;
cout << "Calling a Fortran subroutine" << endl;
cout << "===============================" << endl;
// call to the subroutine -->segmentation fault
fireballess_(ear,ne,parames,ifl,photar,photer);
for (int i=0;i<=ne;i++){
cout << "ear = " <<ear[i-1]<< " - "<<ear[i] << endl;
cout << "photar = " << photar[i] << endl;
cout << "photer = " << photer[i] << endl << endl;
}
delete[] ear;
delete[] parames;
delete[] photar;
delete[] photer;
}
程序在调用子例程时崩溃。我在 C++ 或 Fortran 编码方面不是很有经验,所以我不确定该怎么做。到目前为止,我已经检查了传递给子程序的变量的格式是否正确,看起来是这样。
提前感谢您的帮助
------------编辑------ 阅读一些评论后我修改了代码如下,调用例程时仍然出现相同的分段错误:
using namespace std;
extern "C" void fireballess_( std::vector<float> fear, int fne,std::vector<float> fparames, int fifl, std::vector<float> fphotar, std::vector<float> fphoter);
int main(int argc, char ** argv)
{
int ne,ifl;
ifl=2;
ne = 3;
std::vector<float> parames = {4.3,0.23,0.5,0.5,1.5,1.,1000.,2.15,3.};
std::vector<float> ear={0,20,40};
std::vector<float> photar;
std::vector<float> photer;
cout << "Calling a Fortran subroutine" << endl;
cout << "===============================" << endl;
fireballess_(ear,ne,parames,ifl,photar,photer);
for (int i=0;i<ne;i++){
cout << "ear = " <<ear[i-1]<< " - "<<ear[i] << endl;
cout << "photar = " << photar[i] << endl;
cout << "photer = " << photer[i] << endl << endl;
}
}
从 C 和 C++ 代码调用 Fortran 函数的现代方法是通过 ISO_C_BINDING
,请参见其 tag wiki on SO。没有这个界面会有一些怪癖,比如
- 所有变量都通过引用(指针)传递给 Fortran 函数
- 传递数组时还必须传递它们的长度
- ...
这种古怪的 C/Fortran 互操作方式被描述为例如here.
请注意,您不能将 std::vector
或任何其他复杂的 C++ 对象传递给 C 或 Fortran 函数并期望它会理解它。这很可能不起作用,除非该功能旨在处理此问题。因此,您需要从这些对象中获取实际的 low-level 数据(例如指向数组的指针)并传递它们。
结合评论和其他答案中的各种信息,我猜原始代码的 minimum-modified 版本可能如下所示:
fortsub.f90
subroutine fireballess(ear, ne, parames, ifl, photar, photer)
implicit none
integer ne, ifl
real*4 ear(0:ne), parames(10), photar(ne), photer(ne)
print *, "ear = ", ear
print *, "ne = ", ne
print *, "parames = ", parames
print *, "ifl = ", ifl
print *, "photar = ", photar
print *, "photer = ", photer
print *
print *, "sizeof(integer) = ", sizeof(ne)
print *, "sizeof(real*4) = ", sizeof(ear(1))
end
main.cpp
#include <iostream>
extern "C"
void fireballess_( float *ear, int *ne, float *parames,
int *ifl, float *photar, float *photer );
int main()
{
std::cout << "sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "sizeof(float) = " << sizeof(float) << std::endl;
int ne = 3, ifl = 2;
float *ear = new float[ne + 1] { 0.0f, 20.0f, 40.0f, 60.0f };
float *parames = new float[10]
{ 0.1f, 0.2f, 0.3f, 0.4f, 0.5f,
0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
float *photar = new float[ne] { 1.0f, 2.0f, 3.0f };
float *photer = new float[ne] { 4.0f, 5.0f, 6.0f };
fireballess_( ear, &ne, parames, &ifl, photar, photer );
delete[] ear;
delete[] parames;
delete[] photar;
delete[] photer;
}
这里修改的部分是: (1) Fortran中的real*4
通常对应C++中的float
; (2) 我们需要传递实际参数的地址(特别是 ne
和 ifl
); (3) ear
应该有 ne + 1
元素,因为它在 Fortran 端被定义为 ear(0:ne)
。然后,将代码编译为
$ gfortran-8 -c fortsub.f90
$ g++-8 main.cpp fortsub.o -lgfortran
给出(使用 GCC8 + MacOS10.13)
sizeof(int) = 4
sizeof(float) = 4
ear = 0.00000000 20.0000000 40.0000000 60.0000000
ne = 3
parames = 0.100000001 0.200000003 0.300000012 0.400000006 0.500000000 0.600000024 0.699999988 0.800000012 0.899999976 1.00000000
ifl = 2
photar = 1.00000000 2.00000000 3.00000000
photer = 4.00000000 5.00000000 6.00000000
sizeof(integer) = 4
sizeof(real*4) = 4
如果我们使用std::vector
,对应的代码可能是这样的(通过查看std::vector
上的一些教程...)
// main2.cpp
#include <iostream>
#include <vector>
extern "C"
void fireballess_( float *ear, int *ne, float *parames,
int *ifl, float *photar, float *photer );
using Vecf = std::vector<float>;
int main()
{
int ne = 3, ifl = 2;
Vecf ear { 0.0f, 20.0f, 40.0f, 60.0f };
Vecf parames { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f,
0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
Vecf photar { 1.0f, 2.0f, 3.0f };
Vecf photer { 4.0f, 5.0f, 6.0f };
fireballess_( ear.data(), &ne, parames.data(),
&ifl, photar.data(), photer.data() );
}
这似乎给出了相同的结果(通过将 main.cpp
替换为 main2.cpp
)。