How to call Fortran routine in static library using C

How to call Fortran routine in static library using C

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

10 帖子 / 0 全新
最新文章
如需更全面地了解编译器优化,请参阅优化注意事项

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.

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

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

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.

Steve - Intel Developer Support

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

 

 

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

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.

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

 

 

 

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

发表评论

登录添加评论。还不是成员?立即加入