Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28988 Discussions

passing a character string in c++ t oa dll function in Fortran

Jacob_B_
Beginner
1,254 Views

Hello

I have a fortran dll with a large number of functions receiving character strings as arguments

for example

double precision function func(str1,prop1,prop2,str2) BIND(C,name='cppfunc')

use, intrinsic :: ISO_C_BINDING

!DEC$ ATTRIBUTES DLLEXPORT :: func

implicit none

!define input variables

character, dimension (12), intent(in) :: str1

character, dimension(255), intent(in) :: str2

..

additional processing

on the c++ side I declare a function

extern "C"

{

double cppfunc(char *, double, double, char *);

}

then in the main c++ code I declare the following

char input[12],f[255],path[255];

strcpy_s(input,"somestring");

strcpy_s(path,"some_path");

cppfunc(input,10.0,10.0,path);

using the debugger I see that path is not defined on the fortran side of the dll and the program has an exception

is there any systematic and robust way to pass char string to a fortran function in a dll ?

 

thanks

jac

 

 

0 Kudos
4 Replies
Steven_L_Intel1
Employee
1,254 Views

There's this annoying issue up through Fortran 2008 with passing character values from C to Fortran in that you're forced to declare the argument on the Fortran side as an array of single characters. You don't show us how you fetch the strings received by the Fortran function (or how you deal with the NUL terminator.)

You could use a loop that copies characters, one by one, to a local character variable, or use C_LOC and C_F_POINTER to map to a CHARACTER(255), POINTER variable. (You'd still have to search for CHAR(0) to get the length.

Fortran 2015 adds the ability to have CHARACTER(*) dummy arguments in an interoperable procedure, but this requires that the C code create a "C descriptor" (a Fortran standard thing) to describe it. This will be supported in the 16.0 compiler.

So - what you have shown us should work, as far as it goes, but you didn't show us the important part.

0 Kudos
Jacob_B_
Beginner
1,254 Views

Hi thanks for your message

I have used a simple function that passes the characters from the array to the string

defining a string

character*12 sinput, spath

do I = 1,12

 sinput(i:i) = input(i)

enddo

 

this works fine but when I try to do the same for spath I get an invalid address error.

I then see that on entering the fortran function path has an invalid address

best

jac

 

0 Kudos
Steven_L_Intel1
Employee
1,254 Views

Sorry, I can't do much with code fragments that may not accurately represent the actual code. Can you provide a small but complete test case (including the C++ and Fortran bits) that shows the problem?

0 Kudos
Jacob_B_
Beginner
1,254 Views

Hi

I have now something that works

the F90 side

REAL (C_DOUBLE) function testfunc(str1,a,b,str2,ns1,ns2)BIND(C,name='tfunc')

!DEC$ ATTRIBUTES DLLEXPORT :: testfunc

use, intrinsic :: ISO_C_BINDING

REAL (C_DOUBLE), VALUE , intent(IN) :: a

REAL (C_DOUBLE), VALUE , intent(IN) :: b

INTEGER (C_INT), VALUE , intent(IN) :: ns1

INTEGER (C_INT), VALUE , intent(IN) :: ns2

character(kind=C_CHAR), dimension(ns1) , intent(IN) :: str1

character(kind=C_CHAR), dimension(ns2) , intent(IN) :: str2

 

CHARACTER(ns2) :: lstr2

CHARACTER(ns1) :: lstr1

 

call putstring(lstr1,str1,ns1)

call putstring(lstr2,str2,ns2)

 

testfunc = a*b

return

end function testfunc

 

subroutine testsubroutine(str1,a,b,str2,ns1,ns2,c)BIND(C,name='tsub')

use, intrinsic :: ISO_C_BINDING

!DEC$ ATTRIBUTES DLLEXPORT :: testsubroutine

REAL (C_DOUBLE), VALUE , intent(in) :: a

REAL (C_DOUBLE), VALUE , intent(in) :: b

REAL (C_DOUBLE) , intent(out) :: c

character(kind=C_CHAR), dimension(ns1) , intent(IN) :: str1

character(kind=C_CHAR), dimension(ns2) , intent(IN) :: str2

 

c = b*a

return

end subroutine testsubroutine

 

subroutine putstring(lstr,str,n)

character*n lstr

character str(n)

do i = 1,n

lstr(i:i) = str(i)

enddo

return

end subroutine putstring

 

============================================================

the c++ side

#include <iostream>

#include <string>

extern "C"

{

double tfunc(const char *str1,double a,double b,const char *str2,int ns1,int ns2);

void tsub(char *str1,double a,double b,char *str2,int ns1,int ns2,double *c);

}

void main(void)

{

// char Input1[12],Input2[255];

std::string strInput1,strInput2;

double a=10.0,b=15.0,c;

strInput2 = "C:\\Software\\TREND 2.0";

strInput1 = "TP";

int ns1 = static_cast<int>(strInput1.size());

int ns2 = static_cast<int>(strInput2.size());

c = tfunc(strInput1.c_str(),a,b,strInput2.c_str(),ns1,ns2);

//tsub(Input1,a,b,Input2,ns1,ns2,&c);

double d = c;

}

this way the strings pass perfectly and with their real size

thanks for the stimulating discussion

jac

 

0 Kudos
Reply