3

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.

6
  • I don't understand if you are calling fortran code from c code or vice versa? In other words, where is the "*name" string allocated and set before passing to a function (the c interface or the fortran code?) Commented Nov 11, 2013 at 18:57
  • Sorry, *name is allocated in the Fortran code, which calls the C code. Commented Nov 11, 2013 at 19:11
  • What happens if you CALL MMEINITWRAPPER(TRIM(ADJUSTL(PRMTOP))//c_null_char,...), where c_null_char is a constant from use iso_c_binding, only: c_null_char? Commented Nov 11, 2013 at 19:14
  • What code do you have control over? In C, you would expect a "0" character ("\0") at the end of the string to mark the end of word. It seems that the various fortran compiler treats the TRIMM-ed string differently leaving zeros or not in some cases. Could you add the number of characters in the prototype to have the C code strncpy the first characters? Commented Nov 11, 2013 at 19:16
  • There is no reason, why Fortran code should add zeroes to strings.It always have to be appended manually. Commented Nov 11, 2013 at 19:47

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

2 Comments

2

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.