5 Replies Latest reply: Jul 29, 2014 12:00 PM by Brian Vandenberg RSS

    Possible bug with c interop in fortran

    2720334

      A colleague and I are writing some c interop examples for a book and have come across a possibe bug.

      We are testing passing 2 d arrrays (c99 vla) between fortran, c and c++.

       

      Fortran main program calling c function works.

      C main program calling Fortran subroutine works.

      C++ calling fortran subroutine fails.

       

      here is the fortran soubroutine

       

      *****

       

      subroutine reciprocal(nr,nc,x,y) bind(c,name='reciprocal')

      use iso_c_binding

      implicit none

      integer (c_int) , value :: nr

      integer (c_int) , value :: nc

      real (c_float) , dimension(1:nr,1:nc) , intent(in ) :: x

      real (c_float) , dimension(1:nr,1:nc) , intent(out) :: y

        y=1.0/x

      end subroutine reciprocal

       

      *****

       

      we compile this with

       

      sunf90 -c ch3110.f90 -o ch3110_f.o

       

      we then try compiling the following with

       

      sunCC ch3110.cxx ch3110_f.o

       

      *****

       

      #include <iostream>

       

      using namespace std;

       

      extern "C" void reciprocal(int nr,int nc,float x[nr][nc],float y[nr][nc]);

       

      int main()

      {

        const int nr=2;

        const int nc=5;

        float x[nr][nc];

        float y[nr][nc];

        float t[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0};

        int r;

        int c;

        int i=0;

       

        for (r=0;r<nr;r++)

          for (c=0;c<nc;c++)

          {

            x[r][c]=t[i];

            i++;

          }

       

        cout << " C++ passing a 2d array to Fortran " << endl;

       

        for (r=0;r<nr;r++)

        {

          for (c=0;c<nc;c++)

          {

            cout << x[r][c] << " ";

          }

          cout << endl;

        }

       

        reciprocal(nr,nc,x,y);

       

        for (r=0;r<nr;r++)

        {

          for (c=0;c<nc;c++)

            cout << " 1 / " << x[r][c] << " = " << y[r][c] << endl;

        }

       

        return(0);

      }

       

      *****

       

      and get the following error message

       

      ian@linux-9624:~/document/fortran/third_edition/examples> sunf90 -c ch3110.f90 -o ch3110_f.o

      ian@linux-9624:~/document/fortran/third_edition/examples> sunCC ch3110.cxx ch3110_f.o

      "ch3110.cxx", line 5: Error: An integer constant expression is required within the array subscript operator.

      "ch3110.cxx", line 5: Error: An integer constant expression is required within the array subscript operator.

      "ch3110.cxx", line 5: Error: An integer constant expression is required within the array subscript operator.

      "ch3110.cxx", line 5: Error: An integer constant expression is required within the array subscript operator.

      "ch3110.cxx", line 36: Error: Formal argument x of type float(*)[1] in call to reciprocal(int, int, float(*)[1], float(*)[1]) is being passed float[2][5].

      "ch3110.cxx", line 36: Error: Formal argument y of type float(*)[1] in call to reciprocal(int, int, float(*)[1], float(*)[1]) is being passed float[2][5].

      6 Error(s) detected.

      ian@linux-9624:~/document/fortran/third_edition/examples>

       

      We get the same (or similar) error messages from

       

        g++ and gfortran 4.8.x

        g++ and gfortran 4.10.x

       

          we failed a bug report with the gnu team

          and it is reported as a duplicate of an existing bug.

       

        microsoft C++ and Intel fortran

       

          microsoft do not support C99 vla.

       

      The only combination that we have found that

      works is with the Intel beta versions of their

      fortran and C++ compilers.

       

      Any thoughts?

       

      Ian Chivers

        • 1. Re: Possible bug with c interop in fortran
          Steve.Clamage-Oracle

          As both compilers have told you, the C++ declaration of reciprocal is not valid. The size of an array dimension must be a compile-time constant. The last array dimension can be omitted in contexts where you only declare, not define, the array, like this;

          float foo( float x[10][] );

          but that doesn't help you here. There is also the problem that an array of a given size is not compatible with a generic declaration, or with an array with a different size.

           

          But because Fortran and C/C++ lay out array elements linearly, you can declare the function to take a pointer to the array element type, and cast the array in the call to the same pointer type. Fortran lays out the elements in a different order than C/C++, so your code has to take that into account. In your example, the array does not need to be processed in any particular order, so you are OK.

           

          You can find more about the the Fortran interface to C/C++ in Studio compilers in the Sun Studio 12: Fortran Programming Guide

           

          Now to your example.

           

          Declare the Fortran function in C++ this way:

            extern "C" void reciprocal(int, int, float* x, float* y);

           

          At the point where you call the function, call it this way:

            reciprocal(nr, nc, (float*)x, (float*)y);

           

          This will work as long as the Fortran array is explicit shape or assumed size.  For assumed shape and deferred shape dummies, Studio passes descriptors rather than a pointer to the data.

           

          Finally, when linking Fortran and C++ code, you must use the C++ compiler (CC) to do the link step, and you must use the option -xlang=f90 to get all the libraries linked in the right order:

          CC  ch3110.cxx  ch3110_f.o  -xlang=f90

          Refer to the xlang option in the C++ Users Guide for more information.

          • 2. Re: Possible bug with c interop in fortran
            2720334

            It appears to be a question of standards conformance and what standards :-(

            The gfortran and Intel C++ compilers are tracking the c99

            standard.Microsoft have stated that they will not be supporting c99 in

            their C++ compiler.

             

            I have found a statement that C++14 will support c99 vla.

             

            Jane and I have a

            c99 and Fortran 90 combination where the above syntax works.

             

            source code below.

             

            c source file

            =========

             

            +++++

             

            #include <stdio.h>

             

            void reciprocal(int nr,int nc,float x[nr][nc],float y[nr][nc]);

             

            int main()

            {

              const int nr=2;

              const int nc=5;

              float x[nr][nc];

              float y[nr][nc];

              float t[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0};

              int r;

              int c;

              int i=0;

             

              for (r=0;r<nr;r++)

                for (c=0;c<nc;c++)

                {

                  x[r][c]=t[i];

                  i++;

                }

             

              printf(" C passing a 2d array to Fortran\n");

             

              for (r=0;r<nr;r++)

              {

                for (c=0;c<nc;c++)

                {

                  printf(" %f " , x[r][c]);

                }

                printf("\n");

              }

             

              reciprocal(nr,nc,x,y);

             

              for (r=0;r<nr;r++)

              {

                for (c=0;c<nc;c++)

                {

                  printf(" 1 / %f = %f \n" , x[r][c],y[r][c]);

                }

                printf("\n");

              }

             

              return(0);

            }

             

            +++++

             

            fortran source file

            =============

             

            subroutine reciprocal(nr,nc,x,y) bind(c,name='reciprocal')

            use iso_c_binding

            implicit none

            integer (c_int) , value :: nr

            integer (c_int) , value :: nc

            real (c_float) , dimension(1:nr,1:nc) , intent(in ) :: x

            real (c_float) , dimension(1:nr,1:nc) , intent(out) :: y

              y=1.0/x

            end subroutine reciprocal

             

            +++++

             

            this combination WORKS

            with the sun compiler suite.

             

            Finally you mentiion

             

            +++++

             

            Finally, when linking Fortran and C++ code, you must use the C++ compiler (CC) to do the link step, and you must use the option -xlang=f90 to get all the libraries linked in the right order:

            CC  ch3110.cxx  ch3110_f.o  -xlang=f90

            Refer to the xlang option in the C++ Users Guide for more information.

             

            ++++

             

            jane and i did not need to do the above using c interop with the other mixed language examples

            we have written and have working.

             

            we have a scalar parameter passing example

             

              fortran calling c

            c calling fortran

            c++ calling fortran

             

            that works with the 12.4 beta suite.

             

            we have a 1 d array example

             

              fortran calling c

              c calling fortran

              c++ calling fortran

             

            working with the 12.4 beta suite.

             

            I was under the impression that

             

            sunCC

             

            pointed to the sun C++ compiler.

             

            so from your reply I assume that our example will not work with the current

            sun/oracle C++ compiler, but may work if sun track the C++14

            standard.

             

            here is the source code for our 1d fortran C++ combo

             

            c++

            ===

             

            #include <iostream>

             

            using namespace std;

             

            extern "C" float summation(float *,int );

             

            int main()

            {

              const int n=10;

              float *x;

              int i;

              x = new  float[n];

              for (i=0;i<n;i++)

                x[i]=1.0f;

             

              cout << " C++ passing an array to Fortran " << endl;

              cout << " Sum is " << summation(x,n) << endl;

              return(0);

            }

             

            Fortran

            =====

             

            function summation(x,n) bind(c,name='summation')

            use iso_c_binding

            implicit none

            integer (c_int) , value :: n

            real (c_float), dimension(1:n) , intent(in) :: x

            real (c_float) :: summation

            integer :: i

              summation=sum(x(1:n))

            end function summation

             

            this fortran C++ combo works.

             

            Notes

            ====

             

            From the reply we got from the gnu team they wil be implementing

            the functionality at some point.

             

            Intel already does in their beta.

             

            Microsoft will not as they are not tracking

            c99.

             

            Thanks for you time.

            • 3. Re: Possible bug with c interop in fortran
              Steve.Clamage-Oracle

              Ugh. This new version of the Forum software does not seem to provide an obvious way to differentiate quoted text from reply text. I'll try to address your  points in order without the benefits of quoting.

               

              Standards:

              The C++14 is not out yet, although it is currently being balloted. Voting closes August 15.  Assuming it passes, which it probably will, the latest draft will be the C++14 standard, published probably by the end of the year.

              C++11 and C++14 do not have C99 VLAs, despite what you may have read somewhere. Some features of C99 are included in C++14.

              Some compilers (like gcc) have included other C99 features in their C++ compilers, but those would have to be considered non-standard and unportable extensions.

               

              C and C++ are different languages.

              C is not a proper subset of C++. Finding that a construct works in C is no guarantee that it works in C++, although a lot of standard C is also standard C++. Your original question was about C++, so I'll stick to C++ in this discussion.

               

              No standard for interoperability.

              The ability to mix C++ and Fortran code is not assured by either language standard. As a practical matter, compiler vendors that produce both C++ and Fortran compilers for the same platform often provide ways to mix code, with limitations that vary among implementations. What works with one vendor's compilers might need modification to work with other compilers, or might not work at all. Although I didn't say it explicitly, I was describing how Studio C++ and Fortran work together. In particular, I did not discuss how to mix just Studio C and Fortran.

              I cannot advise you on mixing C++ and Fortran from other vendors.

              • 4. Re: Possible bug with c interop in fortran
                2720334

                Thanks very much for the clarification. I had assumed that c99 vla would become a part of standard C++ at some point. we've changed the 2d array parameter passing between a c++ main program and fortran subtroutine to use the (float*) notation as you  recommended.

                • 5. Re: Possible bug with c interop in fortran
                  Brian Vandenberg

                  Another possible issue you may run into with the original code is that function parameters typed as arrays are implicitly treated (at least in some respects) as pointers instead of arrays:

                   

                  #include <iostream>
                  typedef int IntArray_t[32];
                  struct IntStruct_t { int a[32]; };
                  template <typename T>
                  size_t test( T t ) {
                    return sizeof(t);
                  }
                  int main( int argc, char *argv[] ) {
                    using namespace std;
                    IntArray_t x;
                    int y[32];
                    IntStruct_t z;
                    cout << test( x ) << endl;
                    cout << test( y ) << endl;
                    cout << test( z ) << endl;
                    return 0;
                  }
                  
                  

                   

                  The above example will print the numbers 4, 4, 128.  So long as your C++ code does not depend sizeof or anything similar there shouldn't be an issue, but it's at least worth noting (especially in light of the fact your example is going into a book).

                   

                  -Brian