Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
79 Views

Passing by reference from Fortran to C and back

Dear all,

I read may post in this forum about using C DLLs in Fortran programs. I'm stuck in a problem of basic operations (the main problem here is that I'm a very beginner in such things ....) in passing a string (defined as char) from a C to Fortran. In a C DLL I have this:

	__declspec(dllexport)
		void getArr(char &out)
	{
		strcpy(&out, "hello");
	}

and in a separate Fortran program this:

    program FortranCallC

    implicit none
  
      interface
        subroutine getArr(a) bind(C, name="getArr")
        USE,INTRINSIC :: ISO_C_BINDING
        !DEC$ ATTRIBUTES REFERENCE :: a
        CHARACTER, DIMENSION(*), INTENT(INOUT) :: a
        end subroutine
      end interface 
   
      CHARACTER(LEN=128) :: stringa
    
    call getArr(stringa)
    write(*,*)"->",trim(stringa),"<-"
    
    pause
    end program

The Fortran program displays a strange line in the write(*,*) statement, and, after many posts read and lot of hours wasted, I cannot figure out why. The string I get is like this:

 -> hello                                                             <-

and I cannot trim() it. In the debugger (VS2013) I see many rectangular characters instead of the white spaces pasted here.

I'm sorry if this post could seem obvious, but the solution is hard to find for me.

Secondly, what if I decide to pass the pointer of the string? Can I make it work in the same way? I tried many ways but no success ...

Regards,

Giovanni

0 Kudos
7 Replies
Highlighted
Valued Contributor III
79 Views

What exactly are you trying?  What is getArr function in C supposed to do?

Look into what C strcpy function does with null termination and the functioning of Fortran TRIM intrinsic with the presence of C null termination character in the actual argument variable.

0 Kudos
Highlighted
Valued Contributor III
79 Views

If getArr is supposed to copy certain string information to the address received with blank padding to the right, I suggest you use sprintf function in C.  Also, make the C function parameter a pointer to char and include the maximum number of characters to be copied in the parameter list, like so:

__declspec(dllexport)
void getS(char * s, int lens)
{
   sprintf(s, "%-*s", lens, "Hello");
}
program FortranCallC

   use, intrinsic :: iso_c_binding, only : c_char, c_ptr, c_int, c_loc
   
   implicit none

   interface
   
      subroutine getS(s, lens) bind(C, name="getS")
      
         import :: c_ptr, c_int
         
         implicit none
         
         !.. Argument list
         type(c_ptr), intent(in), value    :: s
         integer(c_int), intent(in), value :: lens

      end subroutine getS
      
   end interface 

   !.. Declarations
   character(kind=c_char,len=128), target :: s
   integer(c_int) :: lens

   !.. Begin execution
   lens = int( len(s), kind=kind(lens) )
   call getS( c_loc(s), lens )
   
   write(*,*)"->",trim(s),"<-"

   pause
   
end program
0 Kudos
Highlighted
Beginner
79 Views

Thanks, the example provided works prefectly! Yes, getArr is supposed to copy certain string information to the address received with blank padding to the right.

Thanks also for the example with the pointer, just a couple of clarifications:

1. what c_loc stands for? We want the C address of the string s, right?

2. why lens must enter in getS with the lenght of 128? to reserve the memory space? (sorry, maybe this is common in C++, but I'm an absolute beginner on this language...)

thanks again

0 Kudos
Highlighted
Black Belt
79 Views

In Fortran, character variables can have various lengths. The notion of a string as a sequence of characters terminated by a null character, which is used in C, does not exist in Fortran. The Fortran character constant 'abc' has length=3, for example but, In C, "abc" is 4 bytes long. There are Fortran rules for what to do when expressions contain character constants and variables of different lengths, and what happens when a character expression is assigned to a character variable of a different length than that of the expression.

When using C/Fortran interoperability facilities, the conventions of C and Fortran have to be reconciled, and the mechanics of doing so can be a bit perplexing when you encounter them for the first time.

0 Kudos
Highlighted
Beginner
79 Views

Thanks all for the replies.

Unfortunately, I have another problem: the code you suggested works fine in 32 bit, but in 64 bit the Intel Fortran compiler says that it cannot find the reference to symbol getS during FortranCallC compilation.

What's wrong? I think that in 64bit the integer memory usage id doubled, but I don't know how to change the code to make it work both in 32 and 64 bit.

0 Kudos
Highlighted
Black Belt
79 Views

How (describe in detail) are you compiling the C and the Fortran?  Are you supplying the import library generated when compiling the C DLL when linking the Fortran executable?

(Note that if your objective is just to get Fortran and C code talking to each other within the same executable module, then you don't need to split the stuff for one particular language out into a separate DLL - DLL's are used for other reasons.)

0 Kudos
Highlighted
Beginner
79 Views

Dear IanH, many thanks for your reply. I have to say sorry: I believed that, when making a new configuration in VS, the "copy settings from" command will copy also target folder. My fault; now the executable works also when compiled in 64bit.

To leave a more valuable information into the forum to other people who'll read this in the future, previous answers allowed to me compile a C++ library (wrapper) with /clr support, that can communicate with a .NET DLL. My final aim is to use a .NET DLL in Fortran language.

I think that the main advantage of this solution rather than compiling the .NET DLL with COM support is that, with this approch, you're not obliged to register with regsvr and no TLB files to manage.

0 Kudos