Search code examples
c++fortransegmentation-faultsubroutine

segmentation fault when calling fortran subroutine in C++


I am trying to call a Fortran subroutine in C++.

this is the subroutine start:

    subroutine fireballess(ear,ne,parames,ifl,photar,photer)
    integer ne,ifl
    real*4 ear(0:ne),parames(10),photar(ne),photer(ne)

The subroutine works fine in Fortran, but when I try to call it in C++ I get a segmentation fault. Here is my code:

    #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;
    }

The program crashes on the call to the subroutine. I am not very experienced in C++ or Fortran coding, so I am not sure about what to do. So far I have checked the format of the variables passed to the subroutine was correct, and it looks so.

Thanks in advance for any help

---------EDIT------ after reading some comments I revised the code as follows, still getting the same segmentation fault error when the routine is invoked:

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;
}

}

Solution

  • Combining various info in the comments and the other answer, I guess a minimum-modified version of the original code may look like this:

    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;
    }
    

    Here, the modified parts are: (1) real*4 in Fortran usually corresponds to float in C++; (2) we need to pass the address of actual arguments (particularly for ne and ifl); and (3) ear should have ne + 1 elements because it is defined as ear(0:ne) on the Fortran side. Then, compiling the codes as

    $ gfortran-8 -c fortsub.f90
    $ g++-8 main.cpp fortsub.o -lgfortran
    

    gives (with 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
    

    If we use std::vector, the corresponding code may look like this (by looking at some tutorials on 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() );
    }
    

    which seems to give the same result (by replacing main.cpp by main2.cpp).