1

Frist off I'm new to combining C (and cpp) with Fortran. And I'm new to Fortran in general. I've been looking at other examples and reading about iso c bind. But I'm confused why this doesn't work. I currently don't have a strong grasp on how pointers work in Fortran with C. I think I'm just not getting the syntax or keywords right or something.

Can someone please explain what I'm doing wrong here?

program main
    use iso_c_binding
    implicit none
    character (len=100) :: string
    interface
        !char *foo2()
        character (kind=c_char, len=1) function foo2() bind(c,name='foo2')
            use iso_c_binding
            implicit none
            character (kind=c_char, len=1) :: output
        end function foo2
        !void foo(char *in)
        subroutine foo(input) bind(c,name='foo')
            use iso_c_binding
            implicit none
            character (kind=c_char, len=1) :: input
        end subroutine foo
        !char *foo3(char *in)
        !TODO:
    end interface
    write(*,'(A)') "In fortran now."
    string = "msg from fortran!"
    write(*,'(A)') "In fortran again."
    call foo(trim(string))
    string = foo2() !WHY DOES THIS NOT WORK?
    write(*,'(A)') trim(string)
end program main
#include <stdio.h>
//Test
void foo(char *in);
char *foo2();

void foo(char *in)
{
    printf("I am in C now.\n");
    printf("%s\n",in);
}

char *foo2() {
    printf("I am in C again.\n");    
    return "msg from C!";
}
#makefile
FC=gfortran
CC=gcc
FFLAGS=-O3 -Wall -Wextra
SRC=main.f90
SRCH=test.c
OBJ=${SRC:.f90=.o} $(SRCH:.h=.o)
TARGET=out

$(TARGET): $(OBJ)
    $(FC) $(FFLAGS) -o $@ $(OBJ)
%.o: %.c
    $(CC) -o $@ -c $<
%.o: %.f90
    $(FC) $(FFLAGS) -o $@ -c $<

clean:
    rm *.o *.mod $(TARGET)
output:
In fortran now.
I am in C now.
msg from fortran!
In fortran again.        
I am in C again.

Expected output:
In fortran now.
I am in C now.
msg from fortran!
In fortran again.        
I am in C again.
msg from C!
boardkeystown
  • 180
  • 1
  • 11
  • 1
    Leaving aside lifetime issues of the C return value, your Fortran `foo2` interface says the function result is a length-1 character. It [isn't](https://stackoverflow.com/q/3852790/3157076) (see also [this](https://stackoverflow.com/q/63412077/3157076)). – francescalus Sep 10 '21 at 10:12
  • 1
    Also, `character (kind=c_char, len=1) :: output` is a declaration which doesn't relate to a dummy argument or function result: it's serving no purpose in that interface block. – francescalus Sep 10 '21 at 10:13

1 Answers1

1

Returning type from foo2() is not C_CHAR but C_PTR.
Here is modified fortran code snippet (C code stays the same):

program main
  use iso_c_binding, only: C_PTR, C_NULL_CHAR, c_f_pointer
  implicit none
  type(C_PTR)             :: cpointer
  character(128), pointer :: fpointer
  character(128)          :: string

  interface ! C interface
    !char *foo2()
    type(C_PTR) function foo2() bind(C, NAME='foo2')
      use iso_c_binding, only: C_PTR
      implicit none
    end function foo2
  end interface ! C interface
   
  ! Get C pointer
  cpointer = foo2()

  ! Convert C into Fortran pointer   
  call c_f_pointer(cpointer, fpointer)

  ! Remove NULL character at the end
  string = fpointer(1:index(fpointer,C_NULL_CHAR)-1)

  write (*,'(A)') trim(string)

end program main
jcerar
  • 467
  • 4
  • 13