- 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