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

Calling C/C++ from Fortran

commbank
Beginner
430 Views

Hi All,

I am trying to call C from Fortran, something which I assume has been done for so many times by others. But somehow I cannot

get it working with Intel Fortran and Microsoft C/C++. It crashes the moment I try to print out the values - with a message

"Program Exception - access violation". It must have corrupted memory but I cannot see where. Below is the code sample for a

simple case (Example 1). Note that I am not using the Fortran 2000 conventions of ISO_C_BINDING yet - because calling C from

Fotran must have been done even before Fortran 2000 I assume. I will use them in Example 2.

Example 1:

==========

// simple.h

#ifdef CFUNCTIONS_EXPORTS

#define CFUNCTIONS_API __declspec(dllexport)

#else

#define CFUNCTIONS_API __declspec(dllimport)

#endif

CFUNCTIONS_API int __stdcall arg1(int a1);

---------------------------------------------------------

// simple.cpp : Defines the entry point for the DLL application.

//

#include "stdafx.h"

#include "simple.h"

CFUNCTIONS_API int __stdcall arg1(const int a1)

{

int b1;

b1 =3;

return 1;

}

---------------------------------------------------------

program Mdriver

!dec$ objcomment lib:'cFunctions.lib'

implicit none

integer :: ii, jj, iCount

integer :: arr(1)

interface

integer function arg1(a1)

!DEC$ ATTRIBUTES C, ALIAS:"?arg1@@YGHH@Z" :: arg1 ! Funny name is obtained from looking into DLL.

!DEC$ ATTRIBUTES VALUE :: a1

integer :: a1

end function arg1

end interface

jj=2

ii = 33

iCount =0

ii = arg1(jj)

iCount = iCount +ii

print *, "This is OK ", iCount

ii = arg1(jj)

iCount = iCount +ii

print *, "This is STILL OK", iCount

ii = arg1(jj)

iCount = iCount +ii

print *, "This WILL CRASH", iCount

print *, "Press Enter to Quit"

read *

end program Mdriver

----------------------------------------------------------

OUtput:

This is OK 1

This is STILL OK 2

forrtl: severe (157): Program Exception - access violation

Image PC Routine Line Source

driver.exe 0040327C Unknown Unknown Unknown

driver.exe 004011CF _MAIN__ 46 Mdriver.f90

driver.exe 004AD3F1 Unknown Unknown Unknown

driver.exe 0044F423 Unknown Unknown Unknown

driver.exe 0044F1ED Unknown Unknown Unknown

kernel32.dll 7C817067 Unknown Unknown Unknown

-----------------------------------------------------------------------------

In a second example, I tried to use the new ISO_C_BINDING built into Fortran 2000/2003 which is supposed to be more C

compatible. I took the example straight from the INtel Fortran Manual. Note that this example has been COPIED by so many

people and published on the Internet, yet the code is FULL OF BUGS and won't compile. I had to fix the code and is presented

below. But I still get the errors that seem to be induced by print statements - which I realise must be memory corruption.

Example 2:

--------------------------------------------------

// IntelExample.h

#ifdef CFUNCTIONS_EXPORTS

#define CFUNCTIONS_API __declspec(dllexport)

#else

#define CFUNCTIONS_API __declspec(dllimport)

#endif

CFUNCTIONS_API int __stdcall C_Library_Function(void* sendbuf, int sendcount, int *recvcounts);

-------------------------------------------------

//IntelExample.cpp

#include "stdafx.h"

#include "IntelExample.h"

CFUNCTIONS_API int __stdcall C_Library_Function(void* sendbuf, int sendcount, int *recvcounts)

{

return 22;

}

--------------------------------------------------

MODULE FTN_C_1

USE, INTRINSIC :: ISO_C_BINDING

END MODULE FTN_C_1

MODULE FTN_C_2

INTERFACE

INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION(SENDBUF, SENDCOUNT, RECVCOUNTS) BIND(C, NAME='C_Library_Function')

!DEC$ ATTRIBUTES C, ALIAS:"?C_Library_Function@@YGHPAXHPAH@Z" :: C_LIBRARY_FUNCTION

USE FTN_C_1

IMPLICIT NONE

TYPE (C_PTR), VALUE :: SENDBUF

INTEGER (C_INT), VALUE :: SENDCOUNT

TYPE (C_PTR), VALUE :: RECVCOUNTS

END FUNCTION C_LIBRARY_FUNCTION

END INTERFACE

END MODULE FTN_C_2

program Mdriver

USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC

USE FTN_C_2

!dec$ objcomment lib:'cFunctions.lib'

implicit none

REAL (C_FLOAT), TARGET :: SEND(100)

INTEGER (C_INT) :: SENDCOUNT

INTEGER (C_INT), ALLOCATABLE, TARGET :: RECVCOUNTS(:)

INTEGER :: ii

ii = 47

ALLOCATE( RECVCOUNTS(100) )

ii = C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, C_LOC(RECVCOUNTS))

print *, " hello", ii

print *, "Press Enter to Quit"

read *

end program Mdriver

-------------------------------------------------------------------

Output:

forrtl: severe (157): Program Exception - access violation

Image PC Routine Line Source

driver.exe 00403AE0 Unknown Unknown Unknown

driver.exe 00401172 _MAIN__ 34 IFdriver.f90

driver.exe 004AD5E1 Unknown Unknown Unknown

driver.exe 0044F6E3 Unknown Unknown Unknown

driver.exe 0044F4AD Unknown Unknown Unknown

kernel32.dll 7C817067 Unknown Unknown Unknown

0 Kudos
3 Replies
Steven_L_Intel1
Employee
430 Views

I haven't looked carefully at everything you've tried, but one thing jumps out at me. You used __stdcall on the C++ side which does not match Intel Fortran's defaults. This is at least part of what is causing the access violation errors as you are corruptig the stack.

I also don't understand why you are passing C_LOC of things by value. Why not just pass the thing itself directly (and not use VALUE)?

Please identify the example you say is "full of bugs".

Note that various mixed-language samples are installed along with the compiler. Perhaps you should start with them.

0 Kudos
commbank
Beginner
430 Views

Dear Steve,

Thank you so very much. The thing that jumped at you __stdcall, is the culprit. I removed that and ALL problem solved. Excellent help - very much appreciated.

When I first started constructing these simple tests, I tried to follow the INtel doc method using ISO_C_BINDING. Could not get a simple example to compile. After reading through the documentation - I thought why not put a __stdcall there, even though I don't see why I need. But after putting stdcall, it compiled and ran a few cases. It worked until I found it crashed at various location which I tracked down to a print statement which made even less sense. Hence my original post.

About the buggy examples, I am pasting the exact code sample from Intel Visual Fortran Compiler Documentation below. Funny thing is I found about 3 pdf on the internet on other sites explaining interoperability and they just COPIED the INTEL example with bugs and all (or is it Intel that copied them???) Here is the list of errors.

1. You found this: having the VALUE next to the SENDBUF and RECVCOUNTS declaration

2. It used CALL to C_LIBRARY_FUNCTION but that is not a subroutine, it is a function that returns int.

3. In the ALLOCATABLE statement for RECVCOUNTS, it already dimensioned it for 100.

4. This may not be an error, but it is not clear that for a simple example, it declares

sendbuf as VOID in C code, but in fortran, it passes an array of REAL?

Apologies for using strong words like "FULL oF BUGS", just that I expected an official documentation, when explaining something as crucial and highly technical as C/FOrtran interoperability, to have simple examples that actually compile and work.

I will report the errors to Intel Premier Support next week, unless it turns out that I misunderstood their code somehow.

-----------------------------------------

Example of Fortran Calling C

The following example calls a C function.

C Function Prototype:

int C_Library_Function(void* sendbuf, int sendcount, int *recvcounts);

Fortran Modules:

MODULE FTN_C_1

USE, INTRINSIC :: ISO_C_BINDING

END MODULE FTN_C_1

MODULE FTN_C_2

INTERFACE

INTEGER (C_INT) FUNCTION C_LIBRARY_FUNCTION &

(SENDBUF, SENDCOUNT, RECVCOUNTS) &

BIND(C, NAME=C_Library_Function)

USE FTN_C_1

IMPLICIT NONE

TYPE (C_PTR), VALUE :: SENDBUF

INTEGER (C_INT), VALUE :: SENDCOUNT

TYPE (C_PTR), VALUE :: RECVCOUNTS

END FUNCTION C_LIBRARY_FUNCTION

END INTERFACE

END MODULE FTN_C_2

Fortran Calling Sequence:

USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_FLOAT, C_LOC

USE FTN_C_2

...

REAL (C_FLOAT), TARGET :: SEND(100)

INTEGER (C_INT) :: SENDCOUNT

INTEGER (C_INT), ALLOCATABLE, TARGET :: RECVCOUNTS(100)

...

ALLOCATE( RECVCOUNTS(100) )

...

CALL C_LIBRARY_FUNCTION(C_LOC(SEND), SENDCOUNT, &

C_LOC(RECVCOUNTS))

0 Kudos
Steven_L_Intel1
Employee
430 Views

Thanks for identifying the example. I'm guessing we copied that from somewhere. No need to report to Premier Support - I'll take it up with the writers. Yuck!

0 Kudos
Reply