How should multiple Fortran strings be passed to C? -
to pass fortran string c, hidden parameter passed variable's size. here's working fortran definition, , c (actually c++/cli) method:
interface subroutine appendextension( + filename) + bind(c, name="appendextension") character *1, intent(inout):: filename end subroutine appendextension end interface
and here's c++/cli gets called:
extern "c" { void __declspec(dllexport) __cdecl appendextension( char * name, int buffersize) { string^ clistr = gcnew string(name); clistr = system::io::path::changeextension(clistr->trim(), gcnew string("out")); intptr p = marshal::stringtohglobalansi(clistr); char *pnewcharstr = static_cast<char*>(p.topointer()); int cstrlen = strlen(pnewcharstr); memcpy_s(name, buffersize, pnewcharstr, cstrlen); if (cstrlen < buffersize) { // backfill spaces, since fortran string spaces on right. memset(&name[cstrlen], ' ', buffersize-cstrlen); } marshal::freehglobal(p); }
the above working (intel visual fortran 2013 sp1).
i want pass 2 strings function. here's did:
interface subroutine parsespec( + filename, corename) + bind(c, name="parsespec") character *1, intent(inout):: filename character *1, intent(inout):: corename end subroutine parsespec end interface
here's call in action:
character*80 file_spec character*200 core_name call parsespec(file_spec, core_name)
and here's c++/cli:
void __declspec(dllexport) __cdecl parsespec(char * name, char * corename, int namelen, int corelen) { // namelen , corelen both contain length of "name". ...
there 2 hidden variables. think should buffersizes each of 2 strings, 1 "filename" , 1 "corename". both contain buffer size of first buffer, namely 80.
where going wrong?
the calling convention bind(c) procedures can quite different default calling convention fortran compiler uses fortran fortran calls. should not rely on hidden character length arguments (in general case, shouldn't expect hidden arguments of type int
). suspect have been lucky, given way fortran character variable laid out in memory compiler.
there no need compiler pass length bind(c) procedure, because length of character variable interoperable c one. however, if dummy argument array (which want if passing string, rather individual character), size of array may non-negative - rules of fortran sequence association kind=c_char character mean can associate scalar array.
all - change fortran function declaration such character arguments arrays , add arguments explicitly pass length of arrays.
using free form source, , assuming default character same c_char kind:
interface subroutine parsespec( & name, name_len, & corename, corename_len ) & bind(c, name="parsespec") use, intrinsic :: iso_c_binding, only: c_int, c_char integer(c_int), value :: name_len character(kind=c_char), intent(inout) :: name(name_len) integer(c_int), value :: corename_len character(kind=c_char), intent(inout):: corename(corename_len) end subroutine parsespec end interface use, intrinsic :: iso_c_binding, only: c_int character*80 file_spec character*200 core_name call parsespec( & file_spec, len(file_spec, kind=c_int), & core_name, len(core_name, kind=c_int) )
extern "c" void parsespec( char* name, int name_len, char* corename, int corelen ); // operations on name[0] name[name_len-1] , // corename[0] through corename[core_len-1]...
Comments
Post a Comment