2
votes

I use VS2013 and Intel Visual Fortran, then make a dll from Fortran code. In Fortran subroutine, it has 3 arguments, "fa" for passing a function, "a" for passing an array, "b" for passing a number. But it doesn't work when I call it in VC++.

Update:

Well... program above is chaotic, so I remodify program below. I create a fortran dll that it can pass an array to sum its elements and call a c function.

module callctest

use, intrinsic :: iso_c_binding

implicit none
private
public callcfun

contains    

subroutine callcfun(a,b) bind(C,name = "callcfun")
!DEC$ ATTRIBUTES DLLEXPORT :: callcfun 
    implicit none

    real(c_double), dimension(*):: a !receive an array from c
    type(c_funptr), value :: b ! receive a c function 

    real,  parameter::pi=3.14159
    integer :: i
    real :: sum = 0.0

    do i = 1,3          ! sum the array elements
        sum = sum+a(i)
    end do 
    write(*,*) 'total',sum



    return

end subroutine callcfun

end module callctest 

And c code that it call fortran subroutine:

#include "stdafx.h"
#include <iostream>

using namespace std;

extern "C" {

    void callcfun( double[], void(f)(int)); //

}

void sayhello(int a){


    cout << "Hi! fortran " <<a<< endl;
}
int main(){

    double a[] = { 10.0, 50, 3.0 };

    callcfun(a, sayhello(50));

    system("pause");
    return 0;

}

In c program, function "sayhello" print words "Hi! fortran" and an integer, I want to call sayhello functionby calling "callcfun( array, function )" which is written by fortran.

It works when I call "callcfun( array, function )" in c program if function like "sayhello" only print "Hi! fortran". But I add an int argument for sayhello function so that it print words "Hi! fortran" and an integer argument. Function "callcfun" doesn't execute successfully.

Error list:

Error 1 error C2664: 'void callcfun(double [],void (__cdecl *)(int))' : cannot convert argument 2 from 'void' to 'void (__cdecl *)(int)' c:\users\emlab\documents\visual studio 2013\projects\vc++\call_for_ex\call_for_ex\call_for_ex.cpp 21 1 call_for_ex

2 IntelliSense: argument of type "void" is incompatible with parameter of type "void (*)(int)" c:\Users\EMlab\Documents\Visual Studio 2013\Projects\VC++\call_for_ex\call_for_ex\call_for_ex.cpp 21 14 call_for_ex

Errors show the problem in the c function, how to pass the c function back to fortran dll then call it in fortran?

1
What is "it doesn't work"? Crash, wrong results? Which results? Any error messages? Which messages? - Vladimir F
I add error message above. And maybe my program is not so clear what I want. My object is passing a c function in arraysum then pass it to fortran program. - radiosan

1 Answers

2
votes

For a Fortran procedure to be interoperable, the BIND(C) attribute is required. Both Fortran procedures are missing this attribute.

For a procedure to be exported from a DLL on Windows, the symbolic name of the procedure must ultimately be supplied to the linker. (There are three ways of doing this: a source directive passed through by the compiler into the object code (as per the !DEC$ ATTRIBUTES DLLEXPORT directive used with the arraysum procedure), by listing the procedure name in a module definition file or by listing the name after /EXPORT on the linker command line - I am assuming that the two latter methods have not been used.) Given the source directive approach of nominating one procedure has been used for one of the procedures (arraysum) to be exported, that method should also be used for the other procedure (fcn) that needs to be exported.

For a C++ function to have C linkage, it must be declared with extern "C". There is no such declaration for fcn in the C++ code. (The absence of any declaration for fcn means that C++ code should not have compiled.)

The import library (.lib) generated by the linker when building the Fortran DLL must be provided to the linker when the exe is built from the C++ code. Typically this is done within Visual Studio by providing the import library as an "Additional Dependency" on the Linker > Input property page.