- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi! I create a fortran dll that it can pass an array to sum its elements and call a c function below:
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 with passing c function that it print words and an input integer:
#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; }
But the problem in function sayhello(50). Error list shows:
Error 1 error C2664: 'void callcfun(double [],void (__cdecl *)(int))' : cannot convert argument 2 from 'void' to 'void (__cdecl *)(int)'
IntelliSense: argument of type "void" is incompatible with parameter of type "void (*)(int b)"
How to solve it? Thanks!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think that there is a problem in your C code. In fact, the error message is from the C compiler. The second actual argument to "callcfun" is allowed in C only if is an expression that can be evaluated (including a pointer value). However, your "callcfun" is of type void, so its invocation does not result in a value that can be used as an argument.
It is not clear what you want to accomplish, but you have to conform to the restrictions of C in your C code and the restrictions of Fortran in your Fortran code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In c program, function "sayhello" print words "Hi! fortran" and an integer, I want to call sayhello function
by 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Although you did not say so in so many words, you appear to want a function reference used as an actual argument in the invocation of another function reference to be deferred. There is no provision in either Fortran or C to do such a thing. Since you claim that you can make your idea in pure C, show us the code that does so.
More specifically, how does the C language allow you to distinguish between immediate and deferred evaluation of a function? I don't think this is allowed, but I am willing to be persuaded otherwise.
Here is an example, using the function printf from the standard C library. Given the statement
printf("sqrt(x) = %8.4f",sqrt(x));
where does the sqrt() function get called? Just before the call to printf(), or from deep within printf() itself?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You have problems on your C++ side.
In the Fortran program you have: type(c_funptr), value :: b ! receive a c function
Which declares b as having a C function pointer (.NOT . C++ function pointer)
In the C++ program you have: void sayhello(int a){...}
Which declares sayhello as a C++ function (.NOT. C function (you forgot the extern "C" on this))
In the C++ program you issue: callcfun(a, sayhello(50));
Which "says" evaluate sayhello(50) and use the return (void) as the second argument to callcfun.
My assumption is you need to have callcfun pass:
1) a - the array pointer
2) sayhello - address of sayhello(int) function
3) 50 - the argument you intend to use within the Fortran program (unless you intend to use a Fortran generated integer)
If the above is what you need then the Fortran program needs to add the integer argument (value or reference) and then use
callcfunc(a, sayhello, 50);
Note, depending on how you work the C++ side, you may need to create a temporary function pointer in the event that C++ cannot disambiguate sayhello to be the address of the function. Sometimes use of & helps:
callcfunc(a, &sayhello, 50);
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi! jimdempseyatthecove. After I think for a while, I should adjust my code. Now I call fortran subroutine "callcfun", it includes a function written in C, then in fortran, call "sayhello" that prints words and a number(double format).
My fortran code: module callctest use, intrinsic :: iso_c_binding implicit none interface subroutine cfun(x) use, intrinsic :: iso_c_binding real (kind = c_double), value :: x end subroutine cfun end interface private public callcfun contains subroutine callcfun(b) bind(C,name = "callcfun") !DEC$ ATTRIBUTES DLLEXPORT :: callcfun use, intrinsic :: iso_c_binding implicit none type(c_funptr), value :: b real, parameter::pi=3.14159 procedure(cfun), pointer :: f call c_f_procpointer(b, f) call f(18.12_c_double) end subroutine callcfun end module callctest
And C code:
#include "stdafx.h" #include <iostream> #include <stdio.h> using namespace std; extern "C" { void callcfun(void(*)(double)); } void sayhello(double x){ printf("Hi fortran and x is %f.\n",x); } int main(){ cout << endl; callcfun(&sayhello); system("pause"); return 0; }
But the output is:
Hi fortran and x is -92559592302995111000000000000000000000000000000000000000000000.000000.
Where is my problem? Though I set double format argument in both side, I still cannot find bug.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The problem is (I think) is in the Fortran listing in #6 you declare the interface cfun as being a Fortran function (not C function) taking a "value" of kind(c_double).
Be aware that "value" Fortran functions create a (stack) temporary, copy the value to there, then pass the reference to the value, older Fortran compilers passed an actual value but this precluded them from having an optional value. The newer method protects the content of the original value in the event you somehow manage to write to it.
You need to declare the interface to cfun with BIND(C,...) such that the "value" passes a value on the stack as opposed to reference to value holder. (Note, pass on stack may be supplemented with pass in register)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You are missing BIND(C) on the interface body for `cfun`.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Right! I missed BIND(C) in cfun(x). Thanks for you guys help!
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page