Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28463 Discussions

Mixed language issue: passing data from C to Fortran

sabur
Beginner
238 Views

[cpp]I'm a Fortran user who has a need to call and extract data from a C routine.  I had a question concerning this process several weeks
ago that is contained in the following thread:

http://software.intel.com/en-us/forums/showthread.php?t=61587

(I've upgraded to IVF 11 since then; was using 10.(1?))

I am now able to get Fortran and C codes to link and "see" each other, although it's always possible I may not be doing it
quite right. As far as actually passing data, I'm trying to start small by using the examples in the IVF 11.0 Fortran_Calls_C
example directory. I simply want to pass an integer from the C code to the Fortran and can't seem to be able to do it.

I tried to simplify things with the example codes by just working with "int_arg" and forgetting about the other two arguments.
In the C code I've added the line: int_arg = 2 and I would like to pass this value back to Fortran. Most of the examples and
discussion I can find seem to deal with passing data from Fortran to C when the C routine is called from Fortran.

I cannot get "in_arg" to change value on the Fortran side no matter what I do. I can debug from the C routine (a DLL) and
can see the "int_arg" in the C code change to "2" so I know that the C routine is being called.

I will also need to do this with strings and arrays but for right now I'd be happy just to get a simple integer passed
from C to Fortan. C is new to me, but I've been reading "C Primer Plus" by Prata and am starting to get a very
basic understanding of the language (emphasis on "basic").

Thanks in advance

Mike


Fortran code example from Fortran calling C (IVF 11.0)

! Copyright (C) 2008 Intel Corporation. All Rights Reserved.
!


PROGRAM READDATAFILE
IMPLICIT NONE

! This is an example of a Fortran main program calling
! a C routine. It uses the C Interoperability features
! of Fortran 2003

! Declare the interface for the C routine we'll call
!
INTERFACE
! The BIND(C) tells the compiler that this is an "interoperable"
! procedure. The compiler adjusts the naming conventions as
! appropriate for the companion C processor.
c SUBROUTINE c_routine (int_arg, str_in, str_out) BIND(C)
SUBROUTINE c_routine (int_arg) BIND(C)
USE,INTRINSIC :: ISO_C_BINDING ! Declares C kinds

! First argument is a C "int", passed by value
c INTEGER(C_INT), VALUE,INTENT(IN) :: int_arg
! Second and third arguments are C "char *", represented
! in Fortran by an array of single characters of kind C_CHAR.
! Note that the language allows passing a regular CHARACTER
! variable to such an argument.
c CHARACTER(KIND=C_CHAR),DIMENSION(*) :: str_in,str_out
END SUBROUTINE c_routine
END INTERFACE

c INTEGER int_arg
c COMMON /int_arg/int_arg

CHARACTER(80) OUTPUT_TEXT
INTEGER IN_ARG, OUTPUT_LEN
CHARACTER(80) INPUT_TEXT

INPUT_TEXT = "Testing..."C ! C suffix adds a null terminator
IN_ARG = 123

! Call c_routine. It will return text in OUTPUT_TEXT
!
c CALL c_routine (in_arg, input_text, output_text)
CALL c_routine (in_arg)
! Find the length of the output text, looking
! for the trailing blank
!
OUTPUT_LEN = INDEX(OUTPUT_TEXT," ")
IF (OUTPUT_LEN == 0) OUTPUT_LEN = 80

! Write the string to the console
!
WRITE (*,*) OUTPUT_TEXT(1:OUTPUT_LEN)

END[/cpp]
[cpp]
C/C++ code from Fortran calling C example



/*
! Copyright (C) 2007 Intel Corporation. All Rights Reserved.
!

*/

/* C routine called by Fortran main program
**
** Converts integer input argument to text, appends
** the text to string input argument and stores the
** result in the string output argument
*/

#include

#define DllExport __declspec( dllexport )

extern int int_arg;
__declspec( dllexport ) c_routine();


/*extern c_routine (
int int_arg,
char* input_text,
char* output_text
)
*/
extern c_routine (int int_arg)

{
int_arg = 2;
// sprintf(output_text,"%s%i ",input_text,int_arg);
}

[/cpp]

0 Kudos
3 Replies
rwg
Beginner
238 Views

You made a 'call by value'. If you do this you will never get the value in your C-Routine back to your FORTRAN program. You have to make a 'call by reference'. Change your C-Program to

  1. extern c_routine(int *int_arg)
  2. {
  3. *int_arg=2;
  4. }

and adjust the declarations in your FORTRAN Program.

0 Kudos
TimP
Honored Contributor III
238 Views

Web search, e.g. 'iso_c_binding character array' would show you plenty of examples of the standard way, supported in ifort for about a year now.

0 Kudos
sabur
Beginner
238 Views
Quoting - rwg

You made a 'call by value'. If you do this you will never get the value in your C-Routine back to your FORTRAN program. You have to make a 'call by reference'. Change your C-Program to

  1. extern c_routine(int *int_arg)
  2. {
  3. *int_arg=2;
  4. }

and adjust the declarations in your FORTRAN Program.


Okay, that seemed to work. I may have come close to doing this at one point. However, I was using the IVF version 10 of the example which is quite different than the one in version 11. I just upgraded to version 11 and just discovered that the example in 11 is different; it uses a lot of 2003 interoperability extensions. More stuff to learn and try and figure out, but hopefully the interoperability stuff should make it easier.

The change above worked without making any changes on the Fortran side. What declaration adjustments did you have in mind on the Fortran side?

Thanks.

0 Kudos
Reply