- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page