Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!

How to pass c array to fortran dll

yan__san-chi
Beginner
437 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
Black Belt
437 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

4 Replies
yan__san-chi
Beginner
437 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?

mecej4
Black Belt
437 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).

IanH
Black Belt
438 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

yan__san-chi
Beginner
437 Views

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

Reply