- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As I understand it pass-by-reference is not supported from C++ to Fortran is not supported, or at least not part of the language. Nevertheless it seems to enable passing a value to a Fortran routine whose argument is not declared to have the 'value' attribute. The code below illustrates this:
#ifdef FORTRAN
subroutine mysub1(i) bind(c,name='mysub1')
use iso_c_binding, only: c_int
integer(c_int), intent(in), value :: i
write(*,'(a,i0)') 'mysub1: i = ',i
end subroutine mysub1
subroutine mysub2(i) bind(c,name='mysub2')
use iso_c_binding, only: c_int
integer(c_int), intent(in) :: i
write(*,'(a,i0)') 'mysub2: i = ',i
end subroutine mysub2
subroutine mysub3(i) bind(c,name='mysub3')
use iso_c_binding, only: c_int
integer(c_int), intent(in), value :: i
write(*,'(a,i0)') 'mysub3: i = ',i
end subroutine mysub3
#else
extern "C" {
void mysub1(int&);
void mysub2(int&);
void mysub3(int);
};
int main (int, char**) {
int i=3;
mysub1(i);
mysub2(i);
mysub3(i);
return 0;
}
#endif
To use it save to a file e.g. example.txt then on a command line do the following:
ifort /c /fpp /DFORTRAN /Tf example.txt /free /Foexample_f.obj
cl /Tpexample.txt /Feexample.exe example_f.obj
Then run it: example.exe
mysub1: i = 2357888
mysub2: i = 3
mysub3: i = 3
The way mysub2 is declared seems to give the required behaviour but I don't think it's standards conforming. So my questions are:
1) what are the problems with doing this?
2) can the current behaviour be relied upon?
3) is it advisable to convert to the declaration used in mysub3?
Thanks.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In your usage with mysub1, your result will vary between 32 and 64 bit modes, assuming 32 bit default integer. you have c_intptr_t. As far as I know, Fortran standard doesn't specify anything about c++ reference, but if your c++ follows the usual rules about interoperability between c++ reference and c pointer, you will be ok.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your understanding is not correct - pass-by-reference absolutely is supported and is what you get if you omit the VALUE attribute from an argument to a procedure with BIND(C).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I did have a look at one stage through the C++ standard, and, from what I can remember, I don't think there are rules for interoperability between C pointers and C++ references, and there are explicit differences (references may not require storage and you can't have a pointer to a reference). I think it is a pretty safe assumption that C++ references are implemented using C pointers when they appear in the formal parameter list of the function - it is possible that practical considerations even require that implementation. However, I personally do not rely on this assumption.
To highlight, this (mysub4) is the example that is missing from the code in #1, that shows conforming "pass by reference" (informal sense - neither Fortran nor C++ formally describe things that way).
#ifdef FORTRAN
subroutine mysub1(i) bind(c,name='mysub1')
use iso_c_binding, only: c_int
integer(c_int), intent(in), value :: i
write(*,'(a,i0)') 'mysub1: i = ',i
end subroutine mysub1
subroutine mysub2(i) bind(c,name='mysub2')
use iso_c_binding, only: c_int
integer(c_int), intent(in) :: i
write(*,'(a,i0)') 'mysub2: i = ',i
end subroutine mysub2
subroutine mysub3(i) bind(c,name='mysub3')
use iso_c_binding, only: c_int
integer(c_int), intent(in), value :: i
write(*,'(a,i0)') 'mysub3: i = ',i
end subroutine mysub3
subroutine mysub4(i) bind(c,name='mysub4')
use iso_c_binding, only: c_int
integer(c_int), intent(in) :: i
write(*,'(a,i0)') 'mysub4: i = ',i
end subroutine mysub4
#else
extern "C" {
void mysub1(int&);
void mysub2(int&);
void mysub3(int);
void mysub4(int*);
}
int main (int, char**) {
int i=3;
mysub1(i);
mysub2(i);
mysub3(i);
mysub4(&i); // Pass address of i.
return 0;
}
#endif
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
First of all, Fortran supports interoperability with C, not C++. To the extent that you can make C++ look like C, it works.
Fortran supports interoperability of argument passing two ways. Assuming an interoperable (BIND(C)) interface, Assuming that you're not declaring a dummy argument of a Fortran kind that triggers passing by "C descriptor" (TS29113 or Fortran 2015), the standard says:
- any scalar dummy argument with the VALUE attribute is interoperable with the corresponding formal parameter of the prototype,
- any dummy argument without the VALUE attribute corresponds to a formal parameter of the prototype that is of a pointer type,
It doesn't talk about "pass by reference", but realistically that's what it means by "a formal parameter of the prototype that is of a pointer type".
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page