title: send string from Fortran to Python and back using cffi
body: <p>I was trying to send string from Fortran to Python. After that Python should change the string and send it back to Fortran. This should be accomplish using cffi.</p>
  <p>The below code is based on several answers:</p>
  <ol>
  <li><a href="https://stackoverflow.com/questions/46761159/how-can-i-embed-a-python-function-that-returns-a-string-in-c-using-cffi*/">embeding a Python function that returns string</a></li>
  <li><a href="https://stackoverflow.com/questions/13869528/how-to-pass-arrays-of-strings-from-both-c-and-fortran-to-fortran/13880611#13880611">passing an array of strings from C to a Fortran</a></li>
  <li><a href="https://stackoverflow.com/questions/9686532/arrays-of-strings-in-fortran-c-bridges-using-iso-c-binding">arrays of strings in Fortran-C bridges using iso_c_binding</a></li>
  <li><a href="https://stackoverflow.com/questions/47789533/passing-string-array-from-fortran-to-c-c-dll-and-get-array-with-changed-values">passing string array from Fortran to C and get array with changed values</a></li>
  <li><a href="https://stackoverflow.com/questions/38998241/freeing-a-c-pointer-returned-by-a-c-function-to-fortran">freeing a C pointer returned by a C function to Fortran</a></li>
  </ol>
  <p>The <code>builder.py</code> code:</p>
  <pre><code>from cffi import FFI
  ffi = FFI()
  
  with open('plugin.h') as f:
      data = ''.join([line for line in f if not line.startswith('#')])
      data = data.replace('CFFI_DLLEXPORT', '')
      ffi.embedding_api(data)
  
  ffi.set_source(&quot;my_plugin&quot;, r'''
      #include &quot;plugin.h&quot;
  ''')
  
  with open(&quot;callpy.py&quot;) as f:
      ffi.embedding_init_code(f.read())
  
  ffi.cdef(&quot;&quot;&quot;
      char *strdup(const char *);
  &quot;&quot;&quot;)
  
  ffi.compile(target=&quot;plugin_result.*&quot;, verbose=True)
  </code></pre>
  <p>The <code>callpy.py</code> code:</p>
  <pre><code>from my_plugin import ffi, lib
  
  @ffi.def_extern()
  def interchange_message(nstring, message):
          print('Python received:\n', ffi.string(message).decode(&quot;UTF-8&quot;), '\n')
          message = 'Python says hi!'.ljust(nstring)
          return lib.strdup(bytes(message, 'utf-8'))   # calls malloc()
  </code></pre>
  <p>The <code>plugin.h</code> code:</p>
  <pre><code># ifndef CFFI_DLLEXPORT
  # if defined(_MSC_VER)
  # define CFFI_DLLEXPORT extern __declspec(dllimport)
  # else
  # define CFFI_DLLEXPORT extern
  # endif
  #endif
  CFFI_DLLEXPORT char *interchange_message(int nstring, char message[]);
  </code></pre>
  <p>The <code>program_example.F90</code> code:</p>
  <pre><code>program example
      use :: iso_c_binding
      implicit none
  
      integer(c_int), parameter :: max_string_size = 20
      character(len=max_string_size), target :: initial_message
      character(len=max_string_size) :: final_message
  
      initial_message = &quot;Fortran says hi!&quot;//char(0)!//C_NULL_CHAR
      call interchange_message_Fortran(initial_message, final_message, max_string_size)
      
      WRITE(*,*) 'Fortran received:'
      WRITE(*,*) final_message
  
      contains
          subroutine interchange_message_Fortran(Fortran_string_inserted, Fortran_string_received, string_size)
              use :: iso_c_binding
              interface
                  function interchange_message(nstring, cptr) &amp;
                      result(y) bind(C, name='interchange_message')
                      use iso_c_binding
                      type(c_ptr), value :: cptr
                      integer(c_int), value :: nstring
                      type(c_ptr) :: y
                  end function interchange_message
                  
                  subroutine c_mem_free(W_ptr) bind(C, name='c_mem_free')
                      use :: iso_c_binding
                      type(c_ptr)     :: W_ptr !&lt; The C pointer whose memory needs to be freed
                  end subroutine c_mem_free
              end interface
                  
                  integer(c_int), value, intent(in) :: string_size
                  character(len=string_size),intent(in), target :: Fortran_string_inserted
                  type(c_ptr) :: c_pointer_inserted
                  type(c_ptr) :: c_pointer_received
                  character(len=string_size), pointer :: f_pointer(:)
                  character(len=string_size),intent(inout) :: Fortran_string_received
                  
                  c_pointer_inserted = C_LOC(Fortran_string_inserted)
                  c_pointer_received = interchange_message(string_size, c_pointer_inserted)
                  
                  CALL C_F_POINTER(c_pointer_received, f_pointer, [string_size])
                  Fortran_string_received = TRANSFER(f_pointer, Fortran_string_received)
                  
                  
                  ! if( c_associated(c_pointer_received) ) then
                  !    WRITE(*,*) 'It is pointing to something.'
                  ! end if
  
                  ! apply free()
                  CALL c_mem_free(c_pointer_received)
  
                  ! if( .not. c_associated(c_pointer_received) ) then
                  !    WRITE(*,*) 'It is not pointing anymore.'
                  ! end if
              
          end subroutine interchange_message_Fortran
  
  end program example
  </code></pre>
  <p>The <code>c_mem_free.c</code> code:</p>
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  void c_mem_free (void** W_ptr)
      {
          /* printf(&quot;C is checking what Python sent: '%s'\n&quot;, *W_ptr); */
          free(*W_ptr);
          *W_ptr=NULL;
      }
  </code></pre>
  <p>The above codes produce expected output:</p>
  <pre><code>Python received:
   Fortran says hi!
  
   Fortran received:
   Python says hi!
  </code></pre>
  <p><strong>Question</strong>: In the answer <a href="https://stackoverflow.com/questions/46761159/how-can-i-embed-a-python-function-that-returns-a-string-in-c-using-cffi*/">1.</a> <code>Armin Rigo</code> writes that <em>&quot;the caller must remember to <code>free()</code> it, otherwise a leak occurs&quot;</em>. In my case I created a separated <code>c_mem_free.c</code> code with C <code>c_mem_free</code> function and an interface block for that C function in Fortran code (based on <a href="https://stackoverflow.com/questions/38998241/freeing-a-c-pointer-returned-by-a-c-function-to-fortran">5.</a>).</p>
  <p>I am just wondering if having <code>c_mem_free</code> as a part of the code is really necessary in my case. When I commented <code>CALL c_mem_free(c_pointer_received)</code> in Fortran code I got the same output but it does not mean that it was correct to do so.</p>
  <p><strong>Additional request</strong>: I would very much appreciate if you can please check the code and tell me if something is in my code implementation very wrong, even if the output looks correct.</p>
  <p>Compilation and running commands for the above code on Linux:</p>
  <blockquote>
  <p>python3 builder.py &amp;&amp; gcc -c c_mem_free.c  &amp;&amp; gfortran -c program_example.F90 &amp;&amp; gfortran -o program_example program_example.o c_mem_free.o plugin_result.so &amp;&amp; ./program_example</p>
  </blockquote>