- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
![](/skins/images/98E68944C1FF703B8AC50091329B92AF/responsive_peak/images/icon_anonymous_message.png)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page