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

How to pass c array to fortran dll

yan__san-chi
Beginner
1,181 Views

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!

 

 

0 Kudos
1 Solution
IanH
Honored Contributor II
1,181 Views

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.)

View solution in original post

0 Kudos
4 Replies
yan__san-chi
Beginner
1,181 Views

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?

0 Kudos
mecej4
Honored Contributor III
1,181 Views

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).

0 Kudos
IanH
Honored Contributor II
1,182 Views

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.)

0 Kudos
yan__san-chi
Beginner
1,181 Views

Oh! I am stupid I forget it is subroutine. Thank you for your reminding.

0 Kudos
Reply