当C代码调用Fortran子例程时,分段错误发生在子例程的顶部 [英] Segmentation fault occurs at top of subroutine when C code calls Fortran subroutine

查看:86
本文介绍了当C代码调用Fortran子例程时,分段错误发生在子例程的顶部的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在文件test-Q.cpp中有C ++代码,该代码在文件getqpf.F中调用了Fortran子例程.在文件test-Q.cpp中,我已将Fortran代码声明为外部代码,并且正在使用getqpf_()名称处理约定来调用该函数. gccgfortran编译器正在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代码功能.在使用gfortrangcc编译器的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.

Note that variables such as nsamp are declared as 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子例程时,分段错误发生在子例程的顶部的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆