Segmentation fault occurs at top of subroutine when C code calls Fortran subroutine(C 代码调用 Fortran 子程序时,子程序顶部出现分段错误)
问题描述
我在文件 test-Q.cpp
中有 C++ 代码,它调用文件 getqpf.F
中的 Fortran 子例程.在文件 test-Q.cpp
中,我已将 Fortran 代码声明为外部代码,并使用 getqpf_()
名称修改约定调用该函数.gcc
和 gfortran
编译器正在 GNU/Linux 上使用.
I have C++ code in file test-Q.cpp
that calls a Fortran subroutine in file getqpf.F
. In file test-Q.cpp
, I've declared the Fortran code as external, and I am calling the function using the getqpf_()
name-mangling convention. The gcc
and gfortran
compilers are being used on GNU/Linux.
这是 C++ 文件顶部的片段:
Here is a snippet from the top of the C++ file:
extern "C" {
void getqpf_ (double *tri,
int nsamp,
int lwin,
int nfreqfit,
double dt,
float null,
int L2,
double df,
double *qq,
double *pf,
double *ampls,
double *work1,
double *work2,
double *work3,
double *work4,
int mem,
int morder,
int nfs,
double *xReal,
double *xImag,
double *xAbs,
double *x1,
int cen,
int top,
int bot,
float cut,
int nfst,
int raw);
} // end
这是来自 Fortran 文件的相应片段:
Here is a corresponding snippet from the Fortran file:
subroutine getqpf (tri, nsamp, lwin, nfreqfit, dt, null, L2, df,
1 qq, pf, ampls, work1, work2, work3, work4,
2 mem, morder, nfs, xReal, xImag, xAbs, x1,
3 cen,top,bot, cut,nfst,raw)
integer morder, lwin, nsamp, nfreqfit, delay, nfs
real tri(*)
real qq(*), pf(*), ampls(*)
real * 8 work1(*), work2(*), work3(*), work4(*)
real * 8 xReal(*), xImag(*), xabs(*), x1(*)
real * 8 dt8, cut8, df8
real null, cut
integer nfst
logical mem, L2, cen, top, bot, raw
integer nf
C program logic code starts here
nf = nfreqfit
delay = 0
dt8 = dt
cut8 = cut
Fortran 代码调用其他 C 代码函数.在使用 gfortran
和 gcc
编译器的 GNU/Linux 上,我按以下方式编译并链接了所有文件:
The Fortran code calls other C-code functions. On GNU/Linux using the gfortran
and gcc
compilers I've compiled and linked all of the files in the following manner:
g++ -c test-Q.cpp -I./boost/boost_1_52_0/ -g
gcc -c paul2.c -g
gcc -c paul2_L1.c -g
gcc -c paul6.c -g
gcc -c paul6_L1.c -g
gcc -c fit_slope.c -g
gfortran -c getqpf.F -g
g++ -o test-Q test-Q.o paul2.o paul2_L1.o paul6.o paul6_L1.o fit_slope.o getqpf.o -g
虽然我能够成功构建二进制文件,但在 nf = nfreqfit
行出现了段错误.它位于 Fortran 文件的最顶部.在二进制文件上运行 gdb
会产生以下输出:
Although I am able to build the binary successfully, there is a segfault that occurs at the line nf = nfreqfit
. This is situated at the very top of the Fortran file. Running gdb
on the binary produces the following output:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000406fd3 in getqpf (tri=..., nsamp=Cannot access memory at address 0x3e9
) at getqpf.F:44
44 nf = nfreqfit
这里发生了什么,为什么会出现段错误?似乎没有在 C++ 代码和 Fortran 代码之间正确传递内存.
What is happening here, and why is there a segfault? It appears that memory is not being properly passed between the C++ code and the Fortran code.
更新
正如 IanH 在下面的答案中提到的,问题是由于没有通过引用传递参数.使用 C++,函数必须声明为:
As IanH mentions in the answer below, the problem is due to not passing arguments by reference. Using C++, the function must be declared as:
extern"C" {
void getqpf_ (float *tri,
int &nsamp,
int &lwin,
int &nfreqfit,
float &dt,
float &null,
int &L2,
float &df,
float *qq,
float *pf,
float *ampls,
double *work1,
double *work2,
double *work3,
double *work4,
int &mem,
int &morder,
int &nfs,
double *xReal,
double *xImag,
double *xAbs,
double *x1,
int &cen,
int &top,
int &bot,
float &cut,
int &nfst,
int &raw);
} // end
注意与号的存在.然后,该函数可以在代码中调用为:
Note the presence of the ampersands. Then, the function can be called in the code as:
getqpf_ (tri,
nsamp,
lwin,
nfreqfit,
dt,
null,
L2,
df,
qq,
pf,
ampls,
work1,
work2,
work3,
work4,
mem,
morder,
nfs,
xReal,
xImag,
xAbs,
x1,
cen,
top,
bot,
cut,
nfst,
raw);
注意nsamp
等变量被声明为int nsamp = 1001
.
推荐答案
在支持 MSB 关于使用 F2003 的 C 互操作性的建议时,请注意您的具体问题是通过引用传递/通过值传递不匹配(这仍然是即使在使用 C 互操作性时也必须考虑).典型的 Fortran 实现通过引用传递所有参数,而在 C(++) 中默认是按值传递.在 C++ 方面,请注意所有 int 和 float 参数以及一些 double 参数都缺少指针说明符 (*
).这些参数是按值传递的——但 Fortran 方面没有任何东西可以表明这一点.在 F2003 之前,这通常是使用 Fortran 代码中的编译器特定指令来完成的.
While seconding M.S.B.'s recommendation about using F2003's C interoperability, note that your specific issue is a pass by reference/pass by value mismatch (which is still something that you have to consider even when using C interoperability). Typical Fortran implementations pass all arguments by reference, while in C(++) the default is by value. On the C++ side, note that all of the int and float arguments and some of the double arguments lack the pointer specifier (*
). These arguments are passed by value - but there is nothing on the Fortran side to indicate that. Before F2003 this was usually done using compiler specific directives in the Fortran code.
使用 F2003 的 C 互操作,将参数传递给具有 BIND(C) 属性的过程的默认约定是通过引用.按值传递的参数需要在其声明中具有 VALUE 属性.
Using F2003's C interop, the default passing convention for arguments to procedures with the BIND(C) attribute is by reference. Arguments that are passed by value need to have the VALUE attribute in their declaration.
这篇关于C 代码调用 Fortran 子程序时,子程序顶部出现分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:C 代码调用 Fortran 子程序时,子程序顶部出现分段错误
基础教程推荐
- 从 std::cin 读取密码 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01