- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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

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