For Programmers: Free Programming Magazines  


Home > Archive > Fortran > May 2004 > c++ calling fortran and fortran calling C++









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author c++ calling fortran and fortran calling C++
rom

2004-05-12, 9:09 pm

Hi,
For my application in C++, I need to call a subtroutine in fortran.
This subroutine must call a function of my program. I'm trying to use
pointer of my function but I have segmentation fault.


the fortran code is:


subroutine dlltest [dllexport] (c_msg,e1,e2,e3,i,r,d,str)
c
implicit none

integer i,l,m,length
real*4 r
double precision d
character*128 e1,e2,e3,str,aux,aux2
external c_msg,length

c first, write parameters to a file

open(1,file='test.out',status='unknown')
rewind(1)
c write(1,*) 'function pointer: ',c_msg
write(1,*) 'integer: ',i
write(1,*) 'real: ',r
write(1,*) 'double precision: ',d
write(1,4) str(1:length(str))
4 format('string: "',(a),'"')
close(1)

c next, pass the received parameters to the external subroutine

write(aux,*) i
l=length(aux)
write(aux2,*) r
m=length(aux2)
write(e1,1) aux(1:l),aux2(1:m) ! e1 = i & r
1 format('integer: ',(a),', real: ',(a))
write(aux,*) d
l=length(aux)
write(e2,2) aux(1:l) ! e2 = d
2 format('double precision: ',(a))
write(e3,3) str(1:length(str)) ! e3 = str
3 format('string: "',(a),'"')

call c_msg(e1,e2,e3)

return
end



integer function length(str)
c
c this function returns the length of a string as the
c number of non-space characters (embedded spaces are
c allowed) and shifts the characters to the leftmost
c edge of the string, filling the rest of it with spaces.
c
implicit none

integer i,j,k,l,m
character*(*) str
character*1 tab
tab=char(9)
k=len(str)
do j=k,1,-1
if(str(j:j).ne.' '.and.str(j:j).ne.tab) goto 1
continue
end do
length=0
return
1 do i=1,j
if(str(i:i).ne.' '.and.str(i:i).ne.tab) goto 2
continue
end do
2 length=j-i+1
if(i.eq.1) return
m=1
do l=i,j
str(m:m)=str(l:l)
m=m+1
end do
str(m:k)=' '
return
end



In my application(wxwidgets) I use somethings like this:

- First I define a function
void MaFonction( const char* e1,const char* e2,const char* e3 )
{
.....
}

- I define a pointer

typedef void (*c_msg)(const char * ,const char* ,const char* );
c_msg essaip = &MaFonction;


- I call my dll

typedef void (*inti)(c_msg ,const char*,const char *,const char *,long
*, float*,double*,const char*);
inti pint;
pint = (inti) wxDllLoader::GetSymbol(mydll,"DLLTEST");
.....
pint(essaip,mystring,mystring,mystring,&a,&b,&c,mystring);




I have a segmentation fault and I don't know where is the problem.

thanks for you help
TimC

2004-05-12, 9:09 pm

rom (aka Bruce) was almost, but not quite, entirely unlike tea:
> Hi,
> For my application in C++, I need to call a subtroutine in fortran.
> This subroutine must call a function of my program. I'm trying to use
> pointer of my function but I have segmentation fault.

....
> - First I define a function
> void MaFonction( const char* e1,const char* e2,const char* e3 )
> {


I'm going to soon use a C++ function from fortran, so I think I have
partly figured out what's needed for that direction -- perhaps it is
also applicable in the other direction (what you need). Since you are
dealing with DLLs on some windows emulator, I probably have aboslutely
no idea :)

First, the calling conventions and properties of character arrays,
etc, between C and fortran are very different. And C++ and C differ
(at link time).

Maybe start at (for fortran->C)
http://hpcf.nersc.gov/software/ibm/c_and_f.html
http://owen.sj.ca.us/rkowen/howto/FandC/FandC.call.html

In in the C++ case, what you will have to do, is in the C++ file, put
in your header file:

extern "C" {
void cMyFortranFunction(blah...)
}

write a function cMyFortranFunction(blah...) which is then in "c
mode", and can call fortran code using the usual method for mixing C
and fortran (eg, passing by reference, add an underscore to the
fortran subroutine name, pass lengths of character arrays as silent
last arguments (by value) etc).

Calling C++ from fortran is done similarly: from fortran, call a
cMyCFuction, which is a function prototyped with 'extern "C"', and
then it can call the C++ function (this convoluting is necessary,
because C++ has function overloading, the the real name is mangled in
a way that only your c++ compiler will know about -- but it still
should work because you are still compiling your 'extern "C"' function
with the C++ compilre)

I have no idea where your segfaul is coming from, but it could well be
related to the current "Illegal instruction (core dumped)" thread
going on - you are interepreting your paramaters wrong (remeber, C
passes by value, fortran by reference), or trying to execute data as
code, or maybe deferencing a null, etc.


--
TimC -- http://astronomy.swin.edu.au/staff/tconnors/
I repeat myself when under stress. I repeat myself when under
stress. I repeat myself when under stress. I repeat myself when
under stress. I repeat myself when under stress. I repeat myself
when under stress. I repeat myself when under stress. I repeat
Catherine Rees Lay

2004-05-12, 9:09 pm

In article <553a2fcf.0405110759.79a2d709@posting.google.com>, rom
<mrom34@wanadoo.fr> writes
>Hi,
>For my application in C++, I need to call a subtroutine in fortran.
>This subroutine must call a function of my program. I'm trying to use
>pointer of my function but I have segmentation fault.
>

You don't say what compilers you're using but under Windows every
Fortran compiler I've used also passes a hidden argument for each
character argument giving its length. Sometimes this is straight after
each character argument, sometimes at the end of the list and sometimes
they are passed by value. You'll need to look up your compiler
documentation on this one.

Also you need to make sure that your function is using the same calling
convention as your C++ app uses internally. It's possible that this is
not the same calling convention that it is using when calling the DLL
routine.

Catherine.
>
>the fortran code is:
>
>
>subroutine dlltest [dllexport] (c_msg,e1,e2,e3,i,r,d,str)
>c
> implicit none
>
> integer i,l,m,length
> real*4 r
> double precision d
> character*128 e1,e2,e3,str,aux,aux2
> external c_msg,length
>
>c first, write parameters to a file
>
> open(1,file='test.out',status='unknown')
> rewind(1)
>c write(1,*) 'function pointer: ',c_msg
> write(1,*) 'integer: ',i
> write(1,*) 'real: ',r
> write(1,*) 'double precision: ',d
> write(1,4) str(1:length(str))
>4 format('string: "',(a),'"')
> close(1)
>
>c next, pass the received parameters to the external subroutine
>
> write(aux,*) i
> l=length(aux)
> write(aux2,*) r
> m=length(aux2)
> write(e1,1) aux(1:l),aux2(1:m) ! e1 = i & r
>1 format('integer: ',(a),', real: ',(a))
> write(aux,*) d
> l=length(aux)
> write(e2,2) aux(1:l) ! e2 = d
>2 format('double precision: ',(a))
> write(e3,3) str(1:length(str)) ! e3 = str
>3 format('string: "',(a),'"')
>
> call c_msg(e1,e2,e3)
>
> return
> end
>
>
>
> integer function length(str)
>c
>c this function returns the length of a string as the
>c number of non-space characters (embedded spaces are
>c allowed) and shifts the characters to the leftmost
>c edge of the string, filling the rest of it with spaces.
>c
> implicit none
>
> integer i,j,k,l,m
> character*(*) str
> character*1 tab
> tab=char(9)
> k=len(str)
> do j=k,1,-1
> if(str(j:j).ne.' '.and.str(j:j).ne.tab) goto 1
> continue
> end do
> length=0
> return
>1 do i=1,j
> if(str(i:i).ne.' '.and.str(i:i).ne.tab) goto 2
> continue
> end do
>2 length=j-i+1
> if(i.eq.1) return
> m=1
> do l=i,j
> str(m:m)=str(l:l)
> m=m+1
> end do
> str(m:k)=' '
> return
> end
>
>
>
>In my application(wxwidgets) I use somethings like this:
>
> - First I define a function
> void MaFonction( const char* e1,const char* e2,const char* e3 )
>{
>....
>}
>
> - I define a pointer
>
>typedef void (*c_msg)(const char * ,const char* ,const char* );
>c_msg essaip = &MaFonction;
>
>
> - I call my dll
>
>typedef void (*inti)(c_msg ,const char*,const char *,const char *,long
>*, float*,double*,const char*);
>inti pint;
>pint = (inti) wxDllLoader::GetSymbol(mydll,"DLLTEST");
>....
> pint(essaip,mystring,mystring,mystring,&a,&b,&c,mystring);
>
>
>
>
>I have a segmentation fault and I don't know where is the problem.
>
>thanks for you help


--
Catherine Rees Lay
To email me, use my first name in front of the "at".
mrom34

2004-05-12, 9:09 pm

thanks for your answer.

I don't know wich compilater was used for the fortran dll. I just develop
an IHM and I must use a dll in fortran for calculation.

Currently, I do some test with mixing fortran and C++. I have another dll
wich accept a real,a long,a string , and which return a file with this
values.
I call this dll from my application in C++ and all is ok.

But now, I try to use the dll in the first post and I have some
difficulty.

Jugoslav Dujic

2004-05-13, 6:31 am

mrom34 wrote:
| thanks for your answer.
|
| I don't know wich compilater was used for the fortran dll. I just develop
| an IHM and I must use a dll in fortran for calculation.

Now, that could be a problem...

subroutine dlltest [dllexport] (c_msg,e1,e2,e3,i,r,d,str)

This syntax indicates that this is one of:

1) Microsoft PowerStation 4.0
2) Digital/Compaq visual fortran 5.0-6.6
3) Intel [Visual] Fortran 7 or 8

if the dll is dynamically linked with Fortran run-time library,
you can deduce what it is by seeing its dependencies. If you have
MS Visual C++, there's a tool "Dependency walker" (Depends) in its
program group. You can freely download it from www.dependencywalker.com.

Next, open the dll from Dependency Walker and you will see in
upper left pane its dependencies (normally, Kernel32.dll at least).
If there's a "DFORRT*.dll" as well, it's 2) -- Compaq Visual Fortran.
If "IF***.dll", it's 3). If none, well, that means it's statically
linked.

In the middle right pane, you will see dll exported functions. What's
the exact name (case matters) for dlltest?

| Currently, I do some test with mixing fortran and C++. I have another dll
| wich accept a real,a long,a string , and which return a file with this
| values.
| I call this dll from my application in C++ and all is ok.

Second, fortran string arguments are always passed with hidden length argument.
E.g.

subroutine foo(s, i)
character(*):: s
integer:: i

has C equivalent which is one of:

void foo(char* s, int s_len, int* i) // CVF/FPS default
void foo(char* s, int* i, int s_len) // IVF default

i.e. either immediately following string argument, or at the end of
argument-list.

Third, calling convention matters. CVF/FPS use __stdcall, while
IVF uses __cdecl. __stdcall symbols are by default exported as
"_FOO@4*n", where n=number of arguments, while __cdecl are exported
as "_FOO". However, the function can be renamed on export, so you
cannot be sure. Failure to match the calling convention can lead
either to link errors or ugly "fandango on stack" run-time
misbehaviours.

Note that all I said above are compiler default options -- they
might have been changed one way or another during dll compilation.

--
Jugoslav
___________
www.geocities.com/jdujic

Please reply to the newsgroup.
You can find my real e-mail on my home page above.

mrom34

2004-05-13, 6:31 am

Thanks for your answers.

Cmpilater is visual fortran 5.
I did another test with a dll which call a C++ function but with an
interger,a real,a double for arguments and all is ok. Problem comes from
string. I have an access violation. I hope to solve this problem with your
advices.

mrom34

2004-05-13, 6:31 am

DFORRT.dll is present
there are two dll exported function:
DLLTEST
_DLLTEST@48

Jugoslav Dujic

2004-05-13, 7:40 am

mrom34 wrote:
| DFORRT.dll is present
| there are two dll exported function:
| DLLTEST
| _DLLTEST@48


subroutine dlltest [dllexport] (c_msg,e1,e2,e3,i,r,d,str)
c
implicit none

integer i,l,m,length
real*4 r
double precision d
character*128 e1,e2,e3,str,aux,aux2

In this case, C prototype should be:

extern "C" __stdcall DLLTEST
(
C_MSG, //(typedef for external, or void*)
char* e1,
int e1_len,
char* e2,
int e2_len,
char* e3,
int e3_len,
int& i,
float& r,
double& d,
char* str,
int str_len
)

12 arguments total, which gives 4*12 = ...@48.

C_MSG should be:

typedef C_MSG void (__stdcall)(char*, int, char*, int, char*, int)

(I doubt this is syntax correct declaration as I always forget correct C
typedefs to function, but you get the idea).

--
Jugoslav
___________
www.geocities.com/jdujic

Please reply to the newsgroup.
You can find my real e-mail on my home page above.

mrom34

2004-05-13, 10:32 am

thank you very much
My program work now.

I used your advice. I add new fonction to have the whole string and it
seems to work.

extern "C" void __stdcall MaFonction(char* st1, int st1_len, char* st2,
int st2_len,char* st3, int st3_len )
{
char* str1=new char[st1_len+1]; // C++ memory allocation
for (unsigned int i=0; i<st1_len; i++)
str1[i]=st1[i]; // strncpy is probably nicer here
str1[st1_len]='\0';




Jugoslav Dujic

2004-05-13, 11:40 am

mrom34 wrote:
| thank you very much
| My program work now.
|
| I used your advice. I add new fonction to have the whole string and it
| seems to work.
|
| extern "C" void __stdcall MaFonction(char* st1, int st1_len, char* st2,
| int st2_len,char* st3, int st3_len )
| {
| char* str1=new char[st1_len+1]; // C++ memory allocation
| for (unsigned int i=0; i<st1_len; i++)
| str1[i]=st1[i]; // strncpy is probably nicer here
| str1[st1_len]='\0';

I hope that delete[] str1; is within missing lines :-)

--
Jugoslav
___________
www.geocities.com/jdujic

Please reply to the newsgroup.
You can find my real e-mail on my home page above.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com