Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29282 Discussions

How to call Fortran routine in static library using C

Kipling__Michael
Beginner
1,460 Views

What is the proper calling convention for a C routine to call a Fortran subroutine containing a character variable in the call list.

Example C code:
...
char *strng[1];
fsubr(strng[0]);
...

Example Fortran code:
SUBROUTINE FSUBR(strng)
!DEC$ ATTRIBUTES DECORATE, ALIAS:'fsubr' :: FSUBR
...
CHARACTER*(*) STRNG
...

Using the default calling convention for the Fortran code and __cdecl for the C code I end up with STRNG having an undefined address when I step into the Fortran routine.

Regards, Mike

0 Kudos
9 Replies
FortranFan
Honored Contributor III
1,460 Views

Review this recent forum topic discussion: but also this question has been addressed often at this forum and if you attempt a search you'll find lots of information.

0 Kudos
Kipling__Michael
Beginner
1,460 Views

I had searched and did not find an answer to my question.  The discussion you referred to was for calling C routines from Fortran.  I do not have a problem doing this placing an interface block in the Fortran code.

What I'm trying to do is to call a Fortran routine from a static library using C to make the call.  I had thought that I could add the line
!DEC$ ATTRIBUTES REFERENCE :: STRNG

to the Fortran code to handle the hidden string length, but this results in the compiler errors:
The REFERENCE attribute cannot be used with a passed length CHARACTER variable on this platform
CHARACTER variable 'FILSPC' has no length argument in routines with C or STDCALL attribute

Mike

0 Kudos
Kipling__Michael
Beginner
1,460 Views

BTW I've also tried the following code, but end up with the strng variable being undefined when I step into the routine.

Example Fortran code:
SUBROUTINE FSUBR(strng)
!DEC$ ATTRIBUTES DECORATE, ALIAS:'fsubr' :: FSUBR
!DEC$ ATTRIBUTES REFERENCE :: FSUBR
...
CHARACTER*(*) STRNG
...

Mike

0 Kudos
Steven_L_Intel1
Employee
1,460 Views

You're passing a single character by value - that isn't what Fortran is expecting. Try passing &strng. But use of CHARACTER(*) is a problem because now you don't have the length passed.

Here's the standard approach:

SUBROUTINE FSUBR (STRNG) BIND(C)
CHARACTER, DIMENSION(*) :: STRNG

Note that this gives you an array of characters and no length. It's a bit awkward to deal with this in Fortran but it can be done.

0 Kudos
Kipling__Michael
Beginner
1,460 Views

I modified the C code to be :
...
char *strng[1];
fsubr(&strng);
...

and the Fortran code to be:
SUBROUTINE FSUBR(strng) BIND(C)
...
CHARACTER, DIMENSION(1):: strng
...
 

The debugger does not say undefined address for strng, but does shows garbage characters.

Would it be better to pass an integer variable in the C code call list for the string length?  I could even dimension the character length of the strng variable. (In the actual code,the variable strng is actually a path/filename so Character*(255) would be fine.)

I'm just looking for the best way to pass character variables from C to Fortran static library routines.  I can modify either or both the C and Fortran code.

Mike

 

 

0 Kudos
Kipling__Michael
Beginner
1,460 Views

OK, I found a solution in the Reference Guide, Mixed Language Programming Standard Tools for Interoperability, Data Types, Characters section.

By modifying both the C code and the Fortran code to look like the example I got it to work.

Thanks, Mike

0 Kudos
JVanB
Valued Contributor II
1,460 Views

Although the problem seems  to have been solved, I would like to point out that

char *strng[1];

declares an array of pointers to char with one element, and

fsubr(strng[0]);

passes the first element, a pointer to char, by value and so is equivalent to passing an array of char by reference.

0 Kudos
Kipling__Michael
Beginner
1,460 Views

The actual code I'm working with was written 25 years ago.  The main C routines called C wrapper routines used to call Fortran routines.

The actual routine passed char *strng to the wrapper which called another routine to copy it to the char * strng[1] variable.  This is what was being passed to the Fortran routine.

The solution I found lets me bypass the wrapper routine altogether, and call the Fortran directly from the main C routine.

Solution:
Main C routine:
...
char *strng;
char strng1[1024];
strcpy(strng1,strng)
fsubr(strng1);
...

Fortran code:
SUBROUTINE FSUBR(strng1) BIND(C)
USE,INTRINSIC :: ISO_C_BINDING
...
CHARACTER, DIMENSION(1024) :: strng1
INTEGER s_len
CHARACTER(1024), POINTER :: strng2
call C_F_POINTER(C_LOC(strng1),strng2)
s_len = INDEX(strng1,C_NULL_CHAR) - 1
...
 

Mike

 

 

 

0 Kudos
Kipling__Michael
Beginner
1,460 Views

I now need help expanding the solution I found for passing a string from C to Fortran.
I need to figure out how to pass string arrays to/from C and Fortran.

In the example below, the C routine is passing an array of strings to Fortran and getting back a 2nd array of strings generated by Fortran.

Can anyone tell me how to handle this?

Example C code:
...
char **str_array1;
char **str_array2;
...
fsubr(str_array1, str_array2);
...


SUBROUTINE FSUBR(str_array1, str_array2) BIND(C)
USE,INTRINSIC :: ISO_C_BINDING
...

Mike

0 Kudos
Reply