Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

calling a c++ function from fortran

jj9867
Beginner
1,404 Views
Hi, I am trying to call a c++ function from a fortran program. I have read many other posts, but am still having trouble getting the linker to find my function in a static library and my dll just crashes when the program begins.

here is my c++ function as defined in my program:

extern "C" {
void _stdcall getforce(int *nAtoms, int *atomicNumber, double position[150][3], double force[500], double *energy);
{

if I am compiling into a DLL:

extern "C" __declspec(dllexport) void _stdcall getforce(int *nAtoms, int *atomicNumber, double position[150][3], double force[500], double *energy);

now in the fortran I place:

INTERFACE
SUBROUTINE getforce()
!DEC$ ATTRIBUTES C, ALIAS:'_getforce' :: getforce
END SUBROUTINE
END INTERFACE

I know that the problem is in the interface in the fortran code, but I cannot find a well laid out explanation of the interface statement. I am having trouble because I work in an academic setting and cannot find the fortran manual. Somehow it was not installed with the compiler and I cannot find the install cds....

I don't care how the c function gets implemented either dll or static is fine
Help would be great,
Thanks
JJ
0 Kudos
7 Replies
anthonyrichards
New Contributor III
1,404 Views

Here is what works for me:
In the C++:

extern "C" { void __cdecl USERROUTINE(int *iarg1, int *iarg2, double *rarg1, double *rarg2, double *rarray1, double *rarray2); }
...
...

int i1 i2
double rarg1, rarg2, rarray1[150], rarray2[500]
....
...define all your arguments somewhere here

USERROUTINE(i1, i2, rarg1, rarg2, rarray1, rarray2)

(The __cdecl just adds a leadingunderscore to the routine name to create a symbol for it in the symbol table in the .OBJ file that is generated, with no other decoration.)

In the FORTRAN: (C++ calling Fortran)

SUBROUTINE USERROUTINE(I1, I2, REAL1, REAL2, REALARRAY1, REALARRAY2)
!
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS : '_USERROUTINE' :: USERROUTINE
!DEC$ ATTRIBUTES REFERENCE :: I1, I2,REAL1, REAL2,REALARRAY1, REALARRAY2
!
INTEGER*4 I1,I2
REAL*8 REAL1, REAL2, REALARRAY1(150), REALARRAY2(500)

In the FORTRAN: (Fortran calling C++)

INTERFACE

SUBROUTINE USERROUTINE(I1, I2, REAL1, REAL2, REALARRAY1, REALARRAY2)
!
!DEC$ ATTRIBUTES C, REFERENCE, ALIAS : '_USERROUTINE' :: USERROUTINE
!DEC$ ATTRIBUTES REFERENCE :: I1, I2,REAL1, REAL2,REALARRAY1, REALARRAY2
!
INTEGER*4 I1,I2
REAL*8 REAL1, REAL2, REALARRAY1(150), REALARRAY2(500)

END SUBROUTINE
END INTERFACE

Note that the use of '*' onthe C++ side ensures that pointers to the arguments are passed, which is the same as Fortran pass-by-reference i.e. the memory address containing the valueis passed, not the value. Note that you really should include the array dimensions as arguments (also by reference), otherwise you have to guess in the Fortran how big the arrays are likely to be.
Given access to the C++ code, I like to make Fortran routines uppercase, as that is the default for Fortran. Otherwise the ALIAS must match the possibly-mixed case C++ function/routine name. In the above case, when using the Fortran linker to linkthe Fortran-generated .OBJ with the C++-generated .OBJ, the linker will search for _USERROUTINE in the symbol table.

0 Kudos
Steven_L_Intel1
Employee
1,404 Views
Note also that Anthony resolved the calling convention mismatch you had - STDCALL on the C++ side and C on the Fortran side.
0 Kudos
prfaridd
Beginner
1,404 Views

Hi there,

I've tried to call fortran subroutine in VC++.NET 2003. for that purpose i did following procedure. In doing it with Compaq version pf 2000 I manage to see my fortran subroutine in C++ and run my project.

In Intel fortran with the same procedure I can't see the fortran subroutine. I'm using Intel fortran 9.0.

I've already have intel fortran and don't want to buy compaq version. Please direct me.

thanks

farid

I did following steps in both Copaq VF and Intel VF

Copy the .lib file and put it in the folder wheremy C++ files are.

Add the following to a header file in your C++ project:

extern "C"

{

void __stdcall subroutine name and parametres

}

Choose Add files to project... and add the .lib file.

Under Link|Input(drop down box), add dformt.lib to Object/library modules add libcmt.lib

Also, in Visual Fortran, I went toProject|Settings...|Fortran(tab)|Libraries(drop down)

and select Use Multithreaded Library and Enable Re-entrancy Support

0 Kudos
Steven_L_Intel1
Employee
1,404 Views

I can't tell from your description exactly what you did or what you mean by "can't see the Fortran routine". You also don't say how the .lib was compiled (using which compiler?). The use of "dformt.lib" is for Compaq Fortran only.

There is a mixed Fortran-C example attached to the Samples thread- you may find it useful. The general steps are:

  • Create a Fortran static library project and add it to your existing solution
  • Add your Fortran sources to it
  • In the Fortran project properties, under Libraries, set Disable default library search rules to No and set the Run-Time Library option to match that for what you have for C++ under "Code Generaton"
  • Right click on the C++ project, select Dependencies. Make the Fortran project be a dependent of the C++ project
  • In Visual Studio, select Tools..Options..Projects..VC++ Directories. Add to the Libraries list the Intel Fortrancompiler LIB folder (C:Program FilesIntelCompilerFortran9.0IA32Lib for example)

Now you should be able to build the solution.

Please note that version 9.0 of Intel Fortran is no longer supported. Version 9.1 is current.

0 Kudos
Morteza_N_
Beginner
1,404 Views

I want to call a C++ function from Fortran. To do that, I make a FORTRAN project in Visual Studio 2010. After that I add a Cpp project to that FORTRAN project. The following errors occur when I want to build the program:

Error 1: unresolved external symbol print_C referenced in function MAIN_main.obj    
Error 2:    1 unresolved externals

Following are the Fortran program and C++ function.

Fortran program:

program main

  use iso_c_binding, only : C_CHAR, C_NULL_CHAR
  implicit none

  interface
    subroutine print_c ( string ) bind ( C, name = "print_C" )
      use iso_c_binding, only : C_CHAR
      character ( kind = C_CHAR ) :: string ( * )
    end subroutine print_c
  end interface

  call print_C ( C_CHAR_"Hello World!" // C_NULL_CHAR )
end

C++ function:

# include <stdlib.h>
# include <stdio.h>

void print_C ( char *text )

{
  printf ( "%s\n", text );

  return;
}

Thanks a lot in advance.

0 Kudos
Steven_L_Intel1
Employee
1,404 Views

You have to make the C++ project, which should be a static library, a "Dependent" of the Fortran project. Right click on the Fortran project and select Dependencies. Check the box for the C++ project and click OK. This will cause the C++ project's library to be linked in. I think you did everything else right.

0 Kudos
Lorri_M_Intel
Employee
1,404 Views

If this is truly a C++ file, then you also need to specify that the external name is C-interoperable by putting this construct around your declaration of print_C:

extern "C" {

}

 

 

By default, C++ mangles the external name in interesting ways; the Fortran Bind(c) construct uses the C external name rules.

 

0 Kudos
Reply