- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello, I am struggling a bit with Fortran callbacks that are passed to a C routine. In the course of various experiments with that I came across this problem:
C code:
/* printc.c -- Print a value via a callback */ #include <stdio.h> void print_via_cb( float x, void (*p)(float x) ) { fprintf(stderr,"Callback: %p\n", p ); fprintf(stderr,"Callback: %f\n", x ); (*p)(x); }
Fortran code:
! testcall.f90 -- ! Test callbacks via ISO_C_BINDING ! module mycallback implicit none contains subroutine printvalue( x ) real, value :: x write(*,*) x end subroutine printvalue end module mycallback program testcallback use mycallback use iso_c_binding implicit none real :: x interface subroutine print_via_cb( x, sub ) bind(c, name = 'print_via_cb' ) use iso_c_binding real, value :: x interface subroutine sub(x) real, value :: x end subroutine sub end interface end subroutine print_via_cb end interface x = 1.2 call print_via_cb( x, printvalue ) end program testcallback
The output of this program was:
Callback: 000000013FEE1060
Callback: 1.200000
5.4472619E-39
rather than 1.20000.
If I add BIND(C) to the interface to the argument SUB, I get an error message, stating that the actual routine doesn't have that attribute and should have, but there is no warning or error if I leave it out (with the above result).
I am using Intel Fortran 15.0.1 at this moment.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
At the risk of sounding like a broken record ("What is this record thing you speak of?"), ISO_C_BINDING is just a module with some helpful declarations. Your program here doesn't use anything from it and the USE line could be removed without effect.
BIND(C) is critical, though. As posted here, the Fortran code won't compile, getting the error:
testcall.f90(26): error #8812: This procedure dummy argument to the BIND(C) procedure is not interoperable.
subroutine sub(x)
---------------------------^
You've declared print_via_cb as interoperable (that's what BIND(C) means), and that then requires that all dummy arguments be interoperable, which sub is not.
It is not sufficient to add BIND(C) to the interface of sub, you must also add it to the actual routine, printvalue. Why is this important? Well, leaving aside the fact that otherwise you have a mismatch in procedure characteristics, the VALUE attribute changes its meaning for interoperable procedures. If you don't say BIND(C), the Fortran standard VALUE attribute means "pass a writable anonymous copy by reference." If you DO say BIND(C), it means "pass by value".
We had this wrong for many years - starting with version 10 up through version 14 we treated the VALUE attribute the same as !DEC$ ATTRIBUTES VALUE. In version 14 we added /assume:std_value to get the standard behavior but had it off by default. In version 15 it was turned on by default.
If you add BIND(C) both to the interface for "sub" and to "printvalue", you get the results you want, since the C code is passing the argument by value.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Right, I was assuming more magic than is actually there. Well, struggling on with the actual problem now. Thanks for the clarification.
![](/skins/images/3CECF0550DB8BF54496C114A1FF06FE9/responsive_peak/images/icon_anonymous_message.png)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page