Home > Archive > Fortran > February 2008 > passing a pointer to a function using iso_c_binding
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
passing a pointer to a function using iso_c_binding
|
|
| Damian 2008-02-28, 4:32 am |
|
I'm attempting to dereference a C function pointer declared using the
Fortran 2003 ISO C bindings in gfortran 4.3.0. The code below stores
the C address of the procedure in an entity of type(c_funptr) and then
passes that address to a C++ procedure (wrapped by 'extern "C"'),
which does three things: (1) prints a greeting, (2) explicitly calls a
Fortran procedure that prints a second greeting, and (3) calls the
same Fortran procedure by dereferencing a pointer to it. The first
two steps complete as expected. The third gives the segmentation
fault. Can someone tell me if this code is incorrect or if there is a
bug in the compiler?
Thanks in advance.
Damian
--------------------- Fortran code
-----------------------------------------------------
program main
use iso_c_binding ,only : c_funloc ,c_funptr
use hello ,only : print_hello
implicit none
type(c_funptr) :: hello_subroutine
interface
subroutine call_fortran_from_cpp(hello_from_fortran
) bind(C)
import :: c_funptr
type(c_funptr) :: hello_from_fortran
end subroutine call_fortran_from_cpp
end interface
hello_subroutine = c_funloc(print_hello)
call call_fortran_from_cpp(hello_subroutine)
end program main
module hello
implicit none
contains
subroutine print_hello() bind(C,name='fortran_hello')
print *,'Hello from Fortran.'
end subroutine print_hello
end module hello
--------------------- C++ code
----------------------------------------
#include <iostream>
using namespace std;
extern "C"
{ void extern fortran_hello();
void call_fortran_from_cpp(void (*fun)())
{ cout << "Hello from C++." << endl;
fortran_hello();
(*fun)();
return;
}
}
| |
| James Van Buskirk 2008-02-28, 4:32 am |
| "Damian" <damian@rouson.net> wrote in message
news:6fe671f9-e6fb-434c-9348-e4e41ac53fdb@s12g2000prg.googlegroups.com...
> interface
> subroutine call_fortran_from_cpp(hello_from_fortran
) bind(C)
> import :: c_funptr
> type(c_funptr) :: hello_from_fortran
> end subroutine call_fortran_from_cpp
> end interface
> extern "C"
> { void extern fortran_hello();
> void call_fortran_from_cpp(void (*fun)())
> { cout << "Hello from C++." << endl;
> fortran_hello();
> (*fun)();
> return;
> }
> }
Your C++ function expects a pointer to a function by value.
Either change that to a pointer to a function by reference
or a pointer to a pointer to a function (I don't know the
syntax for either, however) or change your Fortran interface
block to specify passing its argument by value.
Another alternative would be to use C_F_PROCPOINTER to point
a Fortran procedure pointer at what hello_subroutine points at
and then pass the procedure pointer. You would have to change
the interface block to specify a subroutine by reference rather
than a C_FUNPTR by value, however. Doubly awkward in gfortran
which doesn't support procedure pointers yet, so you would
have to punt with Cray pointers in that case.
So many ways to achieve the goal... too bad we can only use one
at a time.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
| glen herrmannsfeldt 2008-02-28, 4:32 am |
| James Van Buskirk wrote:
(snip)
> Your C++ function expects a pointer to a function by value.
> Either change that to a pointer to a function by reference
> or a pointer to a pointer to a function (I don't know the
> syntax for either, however)
#include <stdio.h>
int main() {
void fun(); /* declare a function */
void (*fptr)(); /* a function pointer */
void (**pfptr)(); /* and a function pointer pointer */
fptr=&fun; /* point to the function */
pfptr=&fptr; /* point to the function pointer */
(**pfptr)(); /* double indirect function call */
}
void fun() {
printf("hi there!\n");
}
Note that the & in &fun is optional. A function name without (),
similar to an array name without [], is a pointer. It seems that
&&fun will not generate a function pointer pointer, though.
My machine with gfortran is down now, so I can't test the call
to/from Fortran.
-- glen
| |
| Craig Powers 2008-02-28, 10:19 pm |
| glen herrmannsfeldt wrote:
> It seems that
> &&fun will not generate a function pointer pointer, though.
&fun is a value, and you can't take the address of a value. It needs to
be assigned to something that has an address in order to be able to take
that address.
Note that you could invert the assignments,
pfptr = &fptr;
fptr = &fun;
and I believe the program would be functionally identical.
| |
| Damian 2008-02-28, 10:19 pm |
| Thanks for the very helpful responses! I added the "value" attribute
to the argument being passed into C++. That works fine.
Damian
| |
| glen herrmannsfeldt 2008-02-28, 10:19 pm |
| Craig Powers wrote:
(I wrote)
[color=darkred]
> &fun is a value, and you can't take the address of a value. It needs to
> be assigned to something that has an address in order to be able to take
> that address.
It used to be that you couldn't take the address of an array,
either, but that seems to have changed.
#include <stdio.h>
int main() {
int array[10]; /* declare a array */
int (*arrptr)[]; /* a array pointer */
int (**paptr)[]; /* and a array pointer pointer */
array[3]=3;
arrptr=&array; /* point to the array */
paptr=&arrptr; /* point to the array pointer */
printf("%d\n",(**paptr)[3]); /* double indirect array reference */
}
> Note that you could invert the assignments,
> pfptr = &fptr;
> fptr = &fun;
> and I believe the program would be functionally identical.
Yes, it should work fine that way.
-- glen
| |
| Gerry Ford 2008-02-28, 10:19 pm |
|
"Damian" <damian@rouson.net> wrote in message
news:6fe671f9-e6fb-434c-9348-e4e41ac53fdb@s12g2000prg.googlegroups.com...
>
> I'm attempting to dereference a C function pointer declared using the
> Fortran 2003 ISO C bindings in gfortran 4.3.0. The code below stores
> the C address of the procedure in an entity of type(c_funptr) and then
> passes that address to a C++ procedure (wrapped by 'extern "C"'),
> which does three things: (1) prints a greeting, (2) explicitly calls a
> Fortran procedure that prints a second greeting, and (3) calls the
> same Fortran procedure by dereferencing a pointer to it. The first
> two steps complete as expected. The third gives the segmentation
> fault. Can someone tell me if this code is incorrect or if there is a
> bug in the compiler?
[code elided]
I was poking around to see what the value attribute might be as it does not
turn up in my reference and found this:
C code:
#include
int main(int ac, char *av[])
{
to_Fortran(2);
}
Fortran code:
subroutine to_Fortran(i)
integer, value :: i
print *, i
end
I would guess that Damian put it here:
type(c_funptr), value :: hello_subroutine
I couldn't get an executable together with 4.3.0 and think that I'm missing
a library, as my linker errors looked exactly like this when a helpful party
in c.l.c++ thought I had the same trouble yesterday:
// dam1.cpp
#include <iostream>
using namespace std;
extern "C"
{ void extern fortran_hello();
void call_fortran_from_cpp(void (*fun)())
{ cout << "Hello from C++." << endl;
fortran_hello();
(*fun)();
return;
}
}
// g++ -c dam1.cpp
! damian1.f03
program main
use iso_c_binding ,only : c_funloc ,c_funptr
use hello ,only : print_hello
implicit none
type(c_funptr) :: hello_subroutine
interface
subroutine call_fortran_from_cpp(hello_from_fortran
) bind(C)
import :: c_funptr
type(c_funptr) :: hello_from_fortran
end subroutine call_fortran_from_cpp
end interface
hello_subroutine = c_funloc(print_hello)
call call_fortran_from_cpp(hello_subroutine)
end program main
module hello
implicit none
contains
subroutine print_hello() bind(C,name='fortran_hello')
print *,'Hello from Fortran.'
end subroutine print_hello
end module hello
! gfortran2 -o dam dam1.o damian1.f03
Begin linker complaints:
dam1.o:dam1.cpp:(.text+0xe): undefined reference to `std::string::size()
const'
dam1.o:dam1.cpp:(.text+0x52): undefined reference to
`std::string::operator[](unsigned int) const'
dam1.o:dam1.cpp:(.text+0x8b): undefined reference to
`std::string::operator[](unsigned int) const'
dam1.o:dam1.cpp:(.text+0xcc): undefined reference to
`std::string::operator[](unsigned int) const'
dam1.o:dam1.cpp:(.text+0x116): undefined reference to
`std::ios_base::Init::Init()'
dam1.o:dam1.cpp:(.text+0x135): undefined reference to
`std::ios_base::Init::~Init()'
dam1.o:dam1.cpp:(.text+0x181): undefined reference to `std::cout'
dam1.o:dam1.cpp:(.text+0x186): undefined reference to
`std::basic_ostream<char, std::char_traits<char> >& std::operator<<
<std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char>
>&, char const*)'
dam1.o:dam1.cpp:(.text+0x191): undefined reference to
`std::basic_ostream<char, std::char_traits<char> >& std::endl<char,
std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char>
>&)'
dam1.o:dam1.cpp:(.text+0x197): undefined reference to
`std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
collect2: ld returned 1 exit status
If anyone can read those tea leaves, I'd sure like to know what they mean.
I'll re-read FX's post on this a w ago to see if something applies.
--
Gerry Ford
"Er hat sich georgiert." Der Spiegel, 2008, sich auf Chimpy Eins komma null
beziehend.
| |
| Damian 2008-02-28, 10:19 pm |
| On Feb 28, 5:25 pm, "Gerry Ford" <inva...@invalid.net> wrote:
> "Damian" <dam...@rouson.net> wrote in message
>
> news:6fe671f9-e6fb-434c-9348-e4e41ac53fdb@s12g2000prg.googlegroups.com...
>
>
> [code elided]
>
> I was poking around to see what the value attribute might be as it does not
> turn up in my reference and found this:
>
> C code:
>
> #include
> int main(int ac, char *av[])
> {
> to_Fortran(2);
> }
>
> Fortran code:
> subroutine to_Fortran(i)
> integer, value :: i
> print *, i
> end
>
> I would guess that Damian put it here:
> type(c_funptr), value :: hello_subroutine
>
> I couldn't get an executable together with 4.3.0 and think that I'm missing
> a library, as my linker errors looked exactly like this when a helpful party
> in c.l.c++ thought I had the same trouble yesterday:
>
> // dam1.cpp
> #include <iostream>
> using namespace std;
> extern "C"
> { void extern fortran_hello();
> void call_fortran_from_cpp(void (*fun)())
> { cout << "Hello from C++." << endl;
> fortran_hello();
> (*fun)();
> return;
> }}
>
> // g++ -c dam1.cpp
>
> ! damian1.f03
> program main
> use iso_c_binding ,only : c_funloc ,c_funptr
> use hello ,only : print_hello
> implicit none
> type(c_funptr) :: hello_subroutine
>
> interface
> subroutine call_fortran_from_cpp(hello_from_fortran
) bind(C)
> import :: c_funptr
> type(c_funptr) :: hello_from_fortran
> end subroutine call_fortran_from_cpp
> end interface
>
> hello_subroutine = c_funloc(print_hello)
> call call_fortran_from_cpp(hello_subroutine)
> end program main
>
> module hello
> implicit none
> contains
> subroutine print_hello() bind(C,name='fortran_hello')
> print *,'Hello from Fortran.'
> end subroutine print_hello
> end module hello
> ! gfortran2 -o dam dam1.o damian1.f03
>
> Begin linker complaints:
> dam1.o:dam1.cpp:(.text+0xe): undefined reference to `std::string::size()
> const'
> dam1.o:dam1.cpp:(.text+0x52): undefined reference to
> `std::string::operator[](unsigned int) const'
> dam1.o:dam1.cpp:(.text+0x8b): undefined reference to
> `std::string::operator[](unsigned int) const'
> dam1.o:dam1.cpp:(.text+0xcc): undefined reference to
> `std::string::operator[](unsigned int) const'
> dam1.o:dam1.cpp:(.text+0x116): undefined reference to
> `std::ios_base::Init::Init()'
> dam1.o:dam1.cpp:(.text+0x135): undefined reference to
> `std::ios_base::Init::~Init()'
> dam1.o:dam1.cpp:(.text+0x181): undefined reference to `std::cout'
> dam1.o:dam1.cpp:(.text+0x186): undefined reference to
> `std::basic_ostream<char, std::char_traits<char> >& std::operator<<
> <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char>
> dam1.o:dam1.cpp:(.text+0x191): undefined reference to
> `std::basic_ostream<char, std::char_traits<char> >& std::endl<char,
> std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char>
> dam1.o:dam1.cpp:(.text+0x197): undefined reference to
> `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
> collect2: ld returned 1 exit status
>
> If anyone can read those tea leaves, I'd sure like to know what they mean.
> I'll re-read FX's post on this a w ago to see if something applies.
>
> --
> Gerry Ford
>
> "Er hat sich georgiert." Der Spiegel, 2008, sich auf Chimpy Eins komma null
> beziehend.
I put the value attribute in the interface block:
type(c_funptr) ,value :: hello_from_fortran
I don't think it will work in the declaration in main (above the
interface block) because, as I understand it, it doesn't affect
anything about the way Fortran stores the variable. It just affects
the way it passes the variable to C.
I don't know enough to interpret the read the tea leaves, but I'm
guessing the compiler is having a hard time finding the 'iostream'
library since that is the only one explicitly referenced in the code.
If I'm right, then commenting out the 'cout...' might get the code to
compile. You might also have to comment out the 'namespace' command
since it tells the compiler something about how to interpret the
'cout' command (which I believe would otherwise require extra
qualifiers to tell the compiler where to find excecutable code for
'cout'). Again, I apologize if any of this is off base. I'm not very
knowledgeable about the C++ size of things.
In case it's relevant, here's the Makefile I used to compile
(presumably it will be clear what parts of the code go in what files
-- and also hopefully it will be clear where word wrapping has
occured):
executable = hello
compile_f03= gfortran
compile_c = g++
link = g++
options = -L/opt/gnu/gfortran-4.3.0/lib/gcc/i386-pc-linux-gnu/4.3.0
-L/opt/gnu/gfortran-4.3.0/lib/gcc -L/opt/gnu/gfortran-4.3.0/lib -
lgfortranbegin -lgfortran
$(executable): main.o call_fortran.o hello.o Makefile
$(link) main.o call_fortran.o hello.o -o $(executable) $
(options)
main.o: main.f03 call_fortran.o hello.o Makefile
$(compile_f03) -c main.f03
call_fortran.o: call_fortran.cpp hello.o Makefile
$(compile_c) -c call_fortran.cpp
hello.o: hello.f03 Makefile
$(compile_f03) -c hello.f03
..PHONY : clean
clean :
-rm -f *.exe *.o *.mod $(executable)
| |
|
| > ! gfortran2 -o dam dam1.o damian1.f03
>
> Begin linker complaints:
> dam1.o:dam1.cpp:(.text+0xe): undefined reference to `std::string::size() const'
> [...]
>
> If anyone can read those tea leaves, I'd sure like to know what they
> mean. I'll re-read FX's post on this a w ago to see if something
> applies.
Yes there is, and I think we already had this discussion: to compile C++
code, do not link with gfortran but with "g++ -L/path/to/libgfortran
-lgfortran -lm" (if main program is not in Fortran) or "g++
-L/path/pto/libgfortranbegin -lgfortranbein -L/path/to/libgfortran
-lgfortran -lm".
--
FX
| |
| Gerry Ford 2008-02-29, 4:31 am |
|
"FX" <coudert@alussinan.org> wrote in message
news:fq8hpo$1cp4$1@nef.ens.fr...
>
> Yes there is, and I think we already had this discussion: to compile C++
> code, do not link with gfortran but with "g++ -L/path/to/libgfortran
> -lgfortran -lm" (if main program is not in Fortran) or "g++
> -L/path/pto/libgfortranbegin -lgfortranbein -L/path/to/libgfortran
> -lgfortran -lm".
Thanks, FX, you have undoubtedly the est initials on usenet.
I'm simply replying to get this in my sent items before I do this thing.
Any hints for an announcement on 4.3.0?
--
Gerry Ford
"Er hat sich georgiert." Der Spiegel, 2008, sich auf Chimpy Eins komma null
beziehend.
|
|
|
|
|