- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[bash]int main(int argc, char * argv[]) {...}[/bash]
[bash]extern void FortranRoutine(char * fname, int nlen, ...);
int n = strlen(argv);
FortranRoutine(argv, &n, ...);[/bash]
in Fortran code
[bash]subroutine FortranRoutine(fname, nlen,...) bind(c, name ='FortranRoutine')
use iso_c_binding, only: c_int, c_float, c_char
character(kind=c_char), dimension(*), intent(in) :: fname integer(c_int), intent(in) :: nlen ! here I have a string with fixed length character(len=50) :: param ! and I need to transform my 'fname' (or argv) to fixed length string 'param' ... end subroutine[/bash]
Could you explain me how to do it, please ?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
arguments, then you can use the standard routines that come with Fortran 2003 instead:
get_command, get_command_argument and command_argument_count.
Otherwise things are a trifle tricky, as argv is an array of pointers to strings, something
Fortran does not support directly. You will have to treat the array elements as individual
pointers. Not very helpful, I know, but I do not jave time to explain it in more detail at
the moment.
Regards,
Arjen
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The C main program:
[cpp]#includeThe Fortran subroutine:#include int main(int argc, char *argv[]){ int i; for(i=0; i ,strlen(argv)); } [/cpp]
[fortran] subroutine FtnRoutine(fname, nlen) bind(c, name ='FtnRoutine') use iso_c_binding, only: c_int, c_float, c_char integer(c_int), intent(in), value :: nlen character(kind=c_char), intent(in) :: fname(nlen) ! here I have a string with fixed length character(len=50) :: param do i=1,nlen param(i:i)=fname(i) end doCompile and run:
param(nlen+1:50)=''
write(*,*)' param = ',param return end subroutine [/fortran]
$ gcc -m32 -c caller.c
$ ifort -nofor-main caller.o ssub.f90
$ ./a.out 11 22 33
param = ./a.out
param = 11
param = 22
param = 33
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[fortran]subroutine FortranRoutine(fname, nlen) bind(c, name='FortranRoutine') use, intrinsic :: iso_c_binding, only: c_int, c_char implicit none character(kind=c_char), intent(in) :: fname(*) integer(c_int), intent(in), value :: nlen !---- character(len=nlen) :: param integer :: i !**** forall (i=1:nlen) param(i:i) = fname(i) ! Or do i = 1, nlen; ... print *, param end subroutine FortranRoutine[/fortran]
Option two - map C pointer to Fortran pointer.
[fortran]subroutine FortranRoutine(fname, nlen) bind(c, name='FortranRoutine') use, intrinsic :: iso_c_binding, only: c_ptr, c_int, c_char, c_f_pointer implicit none type(c_ptr), intent(in), value :: fname integer(c_int), intent(in), value :: nlen !---- ! Std quibble - does nlen have to be a /constant-expression/ for this to be conforming? ! I'm not sure... character(len=nlen,kind=c_char), pointer :: param !**** call c_f_pointer(fname, param) print *, param end subroutine FortranRoutine[/fortran]
If you want to send the entire array of strings (i.e. pass argv, which is char ** ):
[fortran]module my_mod implicit none contains ! Because this takes at least one argument by value, an explicit interface is required. subroutine FortranRoutine(...) ! option one or two as above ... end subroutine FortranRoutine subroutine FortranRoutineDeluxe(argc, argv) bind(c, name='FortranRoutineDeluxe') use, intrinsic :: iso_c_binding: c_ptr, c_int interface function strlen(s) bind(c, name='strlen') result(l) use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t implicit none type(c_ptr), intent(in), value :: s integer(c_size_t) :: l end function strlen end interface integer(c_int), intent(in), value :: argc type(c_ptr), intent(in) :: argv(argc) !--- integer :: i integer(c_int) :: l !**** ! Note argv(1) is the program name. do i = 1, ubound(argv,1) l = strlen(argv(i)) call FortranRoutine(argv(i), l) end do end subroutine FortranRoutineDeluxe end module my_mod[/fortran]The C prototype for the full argv option is:
void FortranRoutineDeluxe(int, char **);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
use, intrinsic :: iso_c_binding ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
use, intrinsic :: iso_c_binding ?
To prevent the problems that might occur if you had your own module with the same name, but did not remember that it existed. The INTRINSIC forces the vendor-provided module to be used.
Whatever changes you make to the Fortran part of your sources has no effect on the C compiler. Therefore, you have to know what parameters the Fortran compiler expects (which can be affected by interfaces), whether by value or reference, and make sure that the C caller delivers the expected parameters.
To pass the string length by reference, instead of by value, you would need to create a nonce variable, assign the string length to it, and pass its address -- awkword, and of no benefit here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
![]() |
External Development Guide: Using CALL_EXTERNAL |
![]() |
Fortran Examples
Example: Calling a Fortran Routine Using a C Interface Routine
Calling Fortran is similar to calling C, with the significant difference that Fortran code expects all arguments to be passed by reference and not by value (the C default). This means that the address of the argument is passed rather than the argument itself. This issue is discussed in By-Value and By-Reference Arguments.
A C interface routine can easily extract the addresses of the arguments from the argv
array and pass them to the actual routine which will compute the sum. The arguments f, n, and s
are pointers that are being passed by value. Fortran expects all
arguments to be passed by reference - that is, it expects all arguments
to be addresses. If C passes a pointer (an address) by value, Fortran
will interpret it correctly as the address of an argument. The following
code segments illustrate this. The example_c2f.c
file contains the C interface routine, which would be compiled as illustrated above. The example.f
file contains the Fortran routine that actually sums the array.
In these examples, we assume that the routines are being compiled under
Sun Solaris. The object name of the Fortran subroutine will be sum_array1_
to match the output of the Solaris Fortran compiler. The following are the contents of example_c2f.c
and example.f
:
This example is compiled and linked in a manner similar to that used in
the C example above. For more information on compiling and linking on
your platform, see the README file contained in the external/call_external/Fortran
subdirectory
of the IDL distribution. This directory also contains a makefile, which
builds this example on UNIX platforms. To call the example program from
within IDL:
;Make an array. X = FINDGEN(10) ;A floating result SUM = 0.0 S = CALL_EXTERNAL('example.so', $ 'sum_array', X, N_ELEMENTS(X), sum)
In this example, example.so
is the name of the sharable image file, sum_array
is the name of the entry point, and X and N_ELEMENTS(X) are passed to the called routine as parameters. The returned value is contained in the variable sum.
Hidden Arguments
When passing C null-terminated character strings into a Fortran routine, the C function should also pass in the string length. This extra parameter is added to the end of the Fortran routine call in the C function, but does not explicitly appear in the Fortran routine.
For example, in C:
char * str1= 'IDL'; char * str2= 'ITT'; int len1=3; int len2=3; double data, info; /* Call a Fortran sub-routine named example1 */ example1_(str1, data, str2, info, len1, len2)
In Fortran:
SUBROUTINE EXAMPLE1(STR1, DATA, STR2, INFO) CHARACTER*(*)STR1, STR2 DOUBLE PRECISIONDATA, INFO
Example: Calling a Fortran Routine Using a Fortran
Interface Routine
Calling Fortran is similar to calling C, with the significant difference that Fortran expects all arguments to be passed by reference. This means that the address of the argument is passed rather than the argument itself. See By-Value and By-Reference Arguments for more on this subject.
A Fortran interface routine can be written to extract the addresses of the arguments from the argv
array and pass them to the actual routine which will compute the sum. Passing the contents of each argv
element by value has the same effect as converting the parameter to a normal Fortran parameter.
This method uses the OpenVMS Extensions to Fortran, %LOC and %VAL. On IBM AIX, the LOC function is an intrinsic operator. The syntax of the call, which differs from that used on other platforms, is:
y=loc(x)
Some Fortran compilers may not support these extensions. If your compiler does not, use the method discussed in the previous section for calling Fortran with a C interface routine.
The contents of the file example1.f
are shown
in the following figure. This example is compiled, linked, and called
in a manner similar to that used in the C example above. For more
information on compiling and linking on your platform, see the README
file contained in the external/fortran
subdirectory of the IDL distribution. This directory also contains a makefile, which builds this example on UNIX platforms.
Note This example is written to run under a 32-bit operating system. To run the example under a 64-bit operating system would require modifications; most notably, to declare argv as INTEGER*8 rather than INTEGER*4 . |
To call the example program from within IDL:
X = FINDGEN(10) ; Make an array. sum = 0.0 S = CALL_EXTERNAL('example1.so', $ 'sum_array_', X, N_ELEMENTS(X), sum)
In this example, example1.so
is the name of the sharable image file, sum_array_
is the name of the entry point, and X
and N_ELEMENTS(X)
are passed to the called routine as parameters. The returned value is contained in the variable sum.
Note The entry point name generated by the Fortran compiler may be different than that produced by the C compiler. One of the best ways to find out what name was generated is to use the UNIX nm utility on the object file. See your system's man page for nm for details. |
IDL Online Help (March 06, 2007)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page