- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
First I create Fortran subroutine below:
module showarr
use, intrinsic :: iso_c_binding
implicit none
private
public calltest
contains
subroutine calltest(a,b) bind(C,name = "calltest" )
implicit none
real(c_double),intent(in), dimension(*) :: a
real(c_double),intent(in) :: b
real, parameter::pi=3.14159
integer :: i
real :: sum = 0.0
do i = 1,3
sum = sum+a(i)
end do
write(*,*) 'total',sum
write(*,*) 'Hello World',b*b*pi
return
end subroutine calltest
end module showarr
I want to pass array a and a number b in C program, return summed array elements and circle of area with radius b.
And my C program:
#include "stdafx.h"
#include <iostream>
using namespace std;
extern "C" {
// Prototype for the Fortran Function
double calltest(double [],double );
}
int main(){
double a[] = { 2.0, 1.5, 3.0};
double r = 3.0;
cout << endl;
cout << "call dll output " << calltest(a,r) << endl;
system("pause");
return 0;
}
Ran C code, I got following error list:
Error 1 error LNK2019: unresolved external symbol _calltest referenced in function _main C:\Users\astro\Documents\Visual Studio 2013\Projects\vc\fordll_ex2\fordll_ex2\fordll_ex2.obj fordll_ex2
Error 2 error LNK1120: 1 unresolved externals C:\Users\astro\Documents\Visual Studio 2013\Projects\vc\fordll_ex2\Debug\fordll_ex2.exe 1 1 fordll_ex2
Would someone can help me? Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The !DEC$ thing in #2 just exports the symbol, which won't conflict with the standard BIND(C) stuff.
(There's no need for the Fortran to be in a DLL separate to the C++ code - you could make a static library out of the Fortran stuff and then link that static library with your C++ code to get an executable with both the C++ and Fortran in it.)
In #2, the Fortran source defines a subroutine, while the C++ code declares calltest as a function returning double. To match a Fortran subroutine, the C++ declaration should be `void calltest(...` - i.e. the equivalent of a C++ function that doesn't return anything.
(Or, if you actually want the Fortran thing to return a double, then it needs to be a Fortran function.)
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
After referenced Standard Fortran and C Interoperability, the problem solved.
Modified Fortran code:
module showarr
use, intrinsic :: iso_c_binding
implicit none
private
public calltest
contains
subroutine calltest(a,b) bind(C,name = "calltest")
!DEC$ ATTRIBUTES DLLEXPORT :: calltest
implicit none
real(c_double), dimension(*),intent(in):: a
real(c_double),intent(in),value :: b
real, parameter::pi=3.14159
integer :: i
real :: sum = 0.0
do i = 1,3
sum = sum+a(i)
end do
write(*,*) 'total',sum
write(*,*) 'Hello World',b*b*pi
return
end subroutine calltest
end module showarr
Modified C code:
#include "stdafx.h"
#include <iostream>
using namespace std;
extern "C" {
// Prototype for the Fortran Function
double calltest(double a[],double b);
}
int main(){
double a[] = { 2.0, 50, 3.0};
double r = 5.0;
cout << endl;
cout << "call dll output " << calltest(a,r) << endl;
system("pause");
return 0;
}
The output of conscole:
total 55.00000
Hello World 78.5397529602051
call dll output -1.#IND
What is "call dll output -1.#IND"? Does it can be removed?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It is a bad idea to mix "legacy interoperability", i.e., DEC$ directives, with ISO Fortran-C interoperability.
By default, Fortran passes arguments by reference. Your C routine, the way you wrote it, expects the second argument to be passed by value, and interprets the address on the stack as a double precision number, causing a wreck. The prototype should be ..., double *b).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The !DEC$ thing in #2 just exports the symbol, which won't conflict with the standard BIND(C) stuff.
(There's no need for the Fortran to be in a DLL separate to the C++ code - you could make a static library out of the Fortran stuff and then link that static library with your C++ code to get an executable with both the C++ and Fortran in it.)
In #2, the Fortran source defines a subroutine, while the C++ code declares calltest as a function returning double. To match a Fortran subroutine, the C++ declaration should be `void calltest(...` - i.e. the equivalent of a C++ function that doesn't return anything.
(Or, if you actually want the Fortran thing to return a double, then it needs to be a Fortran function.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh! I am stupid I forget it is subroutine. Thank you for your reminding.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page