Reputation: 1177
I have a problem with passing strings between Fortran and C.
The Fortran subroutine call looks like this:
CALL MMEINITWRAPPER(TRIM(ADJUSTL(PRMTOP)), 0, SALTCON, RGBMAX, CUT)
The C which works with this has the signature:
int mmeinitwrapper_(char *name,
int *igb,
REAL_T *saltcon,
REAL_T *rgbmax1,
REAL_T *cutoff1)
I put some print statements in various places and everything works just fine, until I compile with ifort. In that case, the output looks like this:
Topology file name:
coords.prmtop
coords.prmtop
Topology file name length: 81 13
length in C: 8
read argument: coords.prmtop��*
Reading parm file (coords.prmtop��*)
coords.prmtop��*, coords.prmtop��*.Z: does not exist
Cannot read parm file coords.prmtop��*
With the Portland compiler:
Topology file name:
coords.prmtop
coords.prmtop
Topology file name length: 81 13
length in C: 8
read argument: coords.prmtop
Reading parm file (coords.prmtop)
The lengths in the first set are from Fortran of the untrimmed/unadjusted string and then the trimmed/adjusted string. The length in C is from sizeof(name)/sizeof(name[0])
.
It seems to be passing a section of memory that's too long and in subsequent runs you get different lengths of bad stuff written (though the reported length in C is always 8).
Does anyone have any ideas? It's difficult getting gdb to play nicely with the Fortran/C combination.
Upvotes: 3
Views: 3494
Reputation: 21431
There are several problems here.
sizeof(name)
in C returns the size of the pointer called name. I take it you are on a 64 bit platform - hence you always see 8.
C often expects string length to be determined by a trailing null sentinel character. The absence of that character can produce strange results. We can't be sure whether that is an issue here without more information.
Fortran compilers differ in their passing conventions for the length of a character variable - it may be as an additional thing immediately after a pointer to the character data, or appended to the end of the other arguments. The rules around interoperability of a procedure with the BIND(C) attribute remove the requirement to pass this length as interoperable character variables can only be of length one. We can't be sure whether this is a problem as you don't show an interface block for the subroutine call on the Fortran side.
So... decide on how you are managing string length on the C side (fixed length? terminating null? separately passed length?), adjust the Fortran call appropriately and add an interface block to the Fortran side with BIND(C).
Upvotes: 2
Reputation: 1476
I believe the answer you're looking for is here:
Arrays of strings in fortran-C bridges using iso_c_binding
Basically, fortran "knows" the length of a string but not C so you have to let the C code know somehow by transmitting the fortran length to C and then reacting appropriately in the C code.
This question below explore this issue from a "pure" fortran POV with some insights in the various answers given:
Fortran to C , effect of trim on space allocated to string
And bear in mind that the compilers might exploit some undefined or implementation-specific differences to explain the varied observed behavior.
Also, I just realized you make a mistake by assuming that sizeof
gives the size of the string. It gives the size of the pointer. So sizeof(name)/sizeof(name[0])
is a constant giving the size of a char
which itself is a constant of 8 bytes in C. sizeof(name)
gives the size of a char pointer and sizeof(name[0])
gives the size of a char. The result is a constant 8.
Upvotes: 6