Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

VC++&Fortran mixed-language string problem

owenkid
Beginner
2,673 Views

I posted an early thread this morning, using the C#&Fortran.

But no one give me even a single answer, so I switch to VC++&Fortran(DLL).

But I encounter the same problem:Unhandled exception at 0x10001082 in MFCMainTest.exe: 0xC0000005: Access violation reading location 0x00000007.

Then I switch to so I switch to VC++&Fortran(Static library),then I got another problem:Error1error LNK2019: unresolved external symbol _TEST@12 referenced in function _dynamicLIBSTRING_Cbridge.obj

I put the whole code in the attachment, I hope some guys can get me out of here.

0 Kudos
22 Replies
anthonyrichards
New Contributor III
2,314 Views

I's like to try and help, but I do not have the application needed to read your archived file.

Why noy post it as simple text - It cannot be that large a file surely?

0 Kudos
TimP
Honored Contributor III
2,314 Views
While my linux installation opens this archive automatically, when I am not on my office network which blocks them, of course there are no tools for reading the Microsoft special files.
I would point out that the short sample first posted seems to indicate that the different string termination requirements of the languages are being ignored, unless the DEC$ directives somehow cover this. If you feel that it is necessary to depend on those specific features, rather than standard Fortran, when using C#, my interest declines sharply.
Among the advertised features of C# are relatively easy debugging, so you should be able to step the C# code after returning from Fortran to see if you have in fact programmed a buffer over-run.
As pointed out in recent examples, you can handle null character string termination explicitly in Fortran. The case may also make the point of defensive C programmers about using the strn functions to guard against over-runs.
0 Kudos
owenkid
Beginner
2,314 Views

I thought that theremay besome problems with the project settings, so I put all the solution in one single winrar file.

Thanks for your reply.

________________________________________________

1.Dynamic library

________________________________________________

Fortran:

! dynamiclib.f90
!
! FUNCTIONS/SUBROUTINES exported from dynamiclib.dll:
! dynamiclib - subroutine
!

SUBROUTINE dynamicLIBSTRING(DATA_FILE,Error,Message)

!DEC$ ATTRIBUTES DLLEXPORT::DYNAMICLIBSTRING
!DEC$ ATTRIBUTES ALIAS:"dynamicLIBSTRING"::DYNAMICLIBSTRING
CHARACTER*(*) DATA_FILE
CHARACTER*(*) Message
integer:: Error
OPEN(12,FILE=DATA_FILE,FORM='FORMATTED',MODE='WRITE')
WRITE(12,*) Error
WRITE(12,*) DATA_FILE
WRITE(12,*) Message
CLOSE(12)
END SUBROUTINE

__________________________

bridge.h

#include "stdafx.h"
#include
typedef void (__stdcall *dynamicLIBSTRING)(char * name,int len,int* errnum,char * msg,int len1);
#ifdef __cplusplus
extern "C" {
#endif
_declspec(dllexport) void dynamicLIBSTRING_C(char * name,int len,int errnum,char * msg,int len1);
#ifdef __cplusplus
}
#endif

__________________________

bridge.cpp

#include "stdafx.h"
#include "bridge.h"

extern "C" _declspec(dllexport) void dynamicLIBSTRING_C(char * name,int len,int errnum,char * msg,int len1)
{
HINSTANCE hDLL;
dynamicLIBSTRING dynamicLIBSTRING1;
hDLL=LoadLibrary(TEXT("dynamiclib.dll"));
dynamicLIBSTRING1=(dynamicLIBSTRING)GetProcAddress(hDLL,("dynamicLIBSTRING"));
dynamicLIBSTRING1(name,len,&errnum,msg,len1);
FreeLibrary(hDLL);
}

__________________________

MFCMainTestDlg.cpp

void CMFCMainTestDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
char* name;
name = "123.bdg";
int len = strlen(name);
int errnum = 0;
char* msg;
msg = "";
int len1 = strlen(msg);
dynamicLIBSTRING_C(name,len,errnum,msg,len1);
OnOK();
}

________________________________________________

2.static library

________________________________________________

Fortran:

subroutine TEST(x,y,z)
real*8:: z
open(10,file='alpha.out',form='formatted',status='UNKNOWN')
write(10,'("staticlib:")')
write(10,'(2F10.2)') x,y
z = 10
write(10,'("staticlib1:")')
write(10,'(F10.2)') z
z = x+y
write(10,'("staticlib2:")')
write(10,'(F10.2)') z
end subroutine TEST

__________________________

bridge.h

#include "stdafx.h"
#include
#ifdef __cplusplus
extern "C" {
#endif
void __stdcall TE ST(float *x,float*y,float*z);
#ifdef __cplusplus
}
#endif

__________________________

bridge.cpp

#include "stdafx.h"
#include "bridge.h"

extern "C" _declspec(dllexport) void dynamicLIBSTRING_C(char * name,int len,int errnum,char * msg,int len1)
{
float x = 10;
float y = 10;
float z = 10;
TEST(&x,&y,&z);
}

__________________________

MFCMainTestDlg.cpp

void CMFCMainTestDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
char* name;
name = "123.bdg";
int len = strlen(name);
int errnum = 0;
char* msg;
msg = "";
int len1 = strlen(msg);
dynamicLIBSTRING_C(name,len,errnum,msg,len1);
OnOK();
}
0 Kudos
owenkid
Beginner
2,314 Views

Thanks tim.

My computer justbreakdown today, so I have to rebind the system rightnow. It may take a little time to have VS 2005 & Fortran to be ready. So I can't try your advice rightnow.

You mentioned that "As pointed out in recent examples, you can handle null character string termination explicitly in Fortran", please let me know how to treat character *(*) type with null character string termination.

I think "null character string termination " is the problem, do you think 'decorate directive' make any sense? And the problem I encounter is related to "ANSI&unicode"?

0 Kudos
owenkid
Beginner
2,314 Views

The static library is quite simple, why the C++ compiler give me the error "unresolved external symbol _TEST@12 referenced in function ", God, please save me.

0 Kudos
Steven_L_Intel1
Employee
2,314 Views
Fortran is expecting the character length to be passed in as "hidden" arguments at the end of the list. You can give the arguments the REFERENCE attribute in Fortran to have it not assume that, but then you'll have to use the INDEX function to find the trailing NUL and get the length. There is no option to have Fortran automatically look for the NUL.

In the C code, take out

_stdcall

That is causing the link error.
0 Kudos
owenkid
Beginner
2,314 Views

Thanks Steve.

Didyou mean I have to use the reference directive? I have no idea of the Index function, would you please give some tips.

BTW, I have found this site:http://www.nag.co.uk/numeric/FL/flassocinfo/csharp/g02eafe.cs

in which he can use the arguments in this way: "string mean, int length_mean,string weight, int length_weight,ref int n, ref int m". So I think there may be some kind of setting can automatically look for the NULL. I want to hear your point.

0 Kudos
Steven_L_Intel1
Employee
2,314 Views
I think the reference you found is telling you to have the C code pass the lengths separately. That works too if you make sure to put them at the end of the argument list.

I meant to use:

!DEC$ ATTRIBUTES REFERENCE :: varname

in the Fortran code. This tells the compiler to not look for the passed lengths.

To use INDEX, do something like this:

integer strinng_len
...
string_len = index (string_var, CHAR(0))

Now you can reference string_var(1:string_len)
0 Kudos
owenkid
Beginner
2,314 Views

Thanks Steve.

I use the same way as the reference, but didn't work, why? what's your "That works too if you make sure to put them at the end of the argument list." exactly mean?

0 Kudos
owenkid
Beginner
2,314 Views
BTW, Steve, why I have to give upthe "stdcall" directive?
0 Kudos
Steven_L_Intel1
Employee
2,314 Views
Intel Visual Fortran defaults to the C calling convention. If you try calling an IVF routine with __stdcall, the C++ compiler will use the STDCALL convention which changes the external name and uses the stack a different way. Mixing these two leads to linking errors and/or stack corruption.

I suggest that you study the C_calls_Fortran sample provided with the product. It demonstrates passing strings.
0 Kudos
owenkid
Beginner
2,314 Views

Thanks Steve.

Where can I find the C_calls_Fortran sample, I have been looking around for a lot of times, but can't find.

Myfortran is the evaluation version 9.1 downloaded from this site.

0 Kudos
Steven_L_Intel1
Employee
2,314 Views
The samples are new in version 10. 10.1 is the current version. I would think that an evaluation version of 9.1 expired its license a long time ago.
0 Kudos
owenkid
Beginner
2,314 Views

Thanks,Steve.

I've already fixed my problem with the help of the sample code, the main factor is that the string length argument have to put after all the argument.

And I've also figure out how to connect between C# and Fortran. But I found a newly problem, I can't step into the Fortran code from the C# graphic interface, I have searched around this forum, andcheck "Enable unmanaged code debugging" box ,but still not work, I attach the simple code in the attachment, will youplease figure out the problem?

0 Kudos
Steven_L_Intel1
Employee
2,314 Views
It may be a while before I can try this, but I generally set breakpoints in my Fortran routines - I don't think trying to "step into" is going to work here.
0 Kudos
sumi714
Beginner
2,314 Views

Set the FORTRAN project as Startup instead of C# project and set break point anywhere in the FORTRAN soubroutine. This should work.

If you put a breakpoint in the FORTRAN routine, even if the startup project is C# one, it should stop at there. But Stepping in to the function from C# code doesnt work.

0 Kudos
owenkid
Beginner
2,314 Views
Thanks, steve. The breakpoints is great.
0 Kudos
owenkid
Beginner
2,314 Views
Thanks Sumi, I don't know why, but the break point satisfy me, that's enough.
0 Kudos
sumi714
Beginner
2,314 Views

I have similar problem and that is why I got interested to look at your project. But mine is slightly different, as I am trying to pass a string from C++ code and then change it inside FORTRAN routine and carry back the changed string out of FORTRAN routine.

I have to use CVF (/iface:cvf) calling convention and set "String Length Argument Passing" as "After Individual String Argument". FORTRAN code is as follows

IGET_NS_X.for

SUBROUTINE GetFortranMsg(iMsgID,iChar,szMsg)

!MS$ATTRIBUTES c,alias: '_GetFortranMsg'::GetFortranMsg

INCLUDE 'bbb_X.fi'

CHARACTER,POINTER:: szMsg

INTEGER,POINTER:: iMsgID

INTEGER,POINTER:: iChar

CHARACTER szCopyMsg*260

szCopyMsg = "It is the string inside FORTRAN code."//char(0)

szMsg = szCopyMsg

RETURN

END


C++code is as follows:

Engine.cpp

extern

"C" void GetFortranMsg(int* iMsgID,int*ichar,char* szMsg, size_t length_arg);

...

void

CEngine::PrintMessage()

{

int

iMsgID = 1;

char *szMsg = new char[256];

int ichar=10;

lstrcpy(szMsg,

"This string has been assigned in C++ code.");

int l = strlen(szMsg);

GetFortranMsg(&iMsgID,&ichar,szMsg,l);

AfxMessageBox(szMsg);

if(szMsg)

delete [] szMsg;

}


With above code, I always get the first character of szMsg in FORTRAN code and hence any change made in there would only modify the first character. I have checked the samples provided in IVF 10 and that also behaves in the same way if CVF calling convention is set. Is there any way out other than looping over all along the string length and fetch one character at a time from FORTRAN code.

0 Kudos
Steven_L_Intel1
Employee
2,142 Views
You have declared szMsg in the Fortran code to be CHARACTER*1. I am not sure what you intend by the POINTER attribute there. What you want instead is something like this:

SUBROUTINE GetFortranMsg(iMsgID,iChar,szMsg)

!MS$ATTRIBUTES c,reference,decorate,alias: 'GetFortranMsg'::GetFortranMsg

INCLUDE 'bbb_X.fi'

CHARACTER(*):: szMsg

INTEGER :: iMsgID

INTEGER :: iChar

CHARACTER szCopyMsg*260

szCopyMsg = "It is the string inside FORTRAN code."//char(0)

szMsg = szCopyMsg

RETURN

END


0 Kudos
Reply