- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
We have been successfully calling FORTRAN from C++ and passing strings. We are using VC2005 and Intel FORTRAN 10. Everything works fine in 32bit, but when we switch building 64bit, we are getting crashes immediately when the FORTRAN is called from C++. Everything points to the character string being broken - all the arguments in the subroutineargument list beforethe first character arugmentare fine, but the characters themselves and the remaining arguments after the strings are corrupted.
This leads us to conclude that somehow the C++ to Fortran string handling is different in 64bit to 32bit, which is somewhat suprising, or maybe there is a bug in the Intel 64bit implementation or perhaps the lengths of the strings are being passed somewhat differently or in a different order in 64bit than it is in 32bit.
Any advice is most welcome.
Thank you
Dr Tony Garratt
Senior Numerical Analyst
Reaction Design
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is no fundamental difference in how strings are passed other than that all argument slots are 64-bits wide.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your character string length arguments must come at the end of the list, unless using /iface:cvf.
If this isn't sufficient to answer the question, please show an actual example.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you so much - of course, the answer is obvious now that you point it out (as always with answers to questions!). We are usingstdcall which isnt available for 64bit, so we have to change our code to pass the string lengths at the end of the argument list.
regards,
Tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It sounds as if you were using CVF conventions on IA-32, which among other things would cause string lengths to be passed after the string address. Did you use the same option on the 64-bit compile? What exactly did you say to get CVF conventions? The "CVF" option for calling convention or explicit STDCALL, NOMIXED_STR_LEN_ARG, REFERENCE attributes?
It may be that the compiler is not putting the string length in the proper position when CVF conventions are requested on x64. I'll have to try that and see.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Steve,
We were using the STDCALL (CVF calling convention) option in our code - passing the characters as (char*, t_size) pairs, which worked fine on IA-32. We used the same option when compiling 32 and 64bit because we used the same code base.
But the compiler documention for Intel 10 says that STDCALL isnt supported on 64bit (see below help from the iface help page - incidentally we didnt use iface, just put STDCALL in the subroutine declaration) which makes me think we need to change all our code to use the default convention (with the string lengths passed at the end).
What do you think?
Description
This option specifies the default calling convention for an application or the argument-passing convention used for hidden-length character arguments.
On systems using IA-32 architecture, you can change the default calling convention by using one of the following methods:
-
Specify /iface:cref, /iface:cvf, /iface:stdcall, or /iface:stdref
-
Specify the ATTRIBUTES directive (using the C, STDCALL, REFERENCE, or VALUE option) in an explicit interface
The second method overrides the first.
On systems using Intel 64 architecture, you cannot change the default calling convention because only one calling convention exists on those systems.
On On systems using IA-64 architecture, the only option available is /iface:default.
| Option | Description |
|---|---|
| /iface:default | Tells the compiler to use the default calling conventions. This is the only option available on systems using IA-64 architecture. |
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- STDCALL calling mechanism
- Arguments passed by reference
- Routine name upcased and decorated with leading underscore and trailing @n
- String lengths passed immediately following string address
I verified that you can set /iface:cvf on Intel 64 (including in Visual Studio) and that it does indeed change where string lengths are passed. Since there is only one calling mechanism, the "STDCALL" part is ignored, as I assume it would be in C++.
I'm missing part of the story here. Your code should have worked just fine if you used the same project options on Intel 64 as you did on IA-32. All I can think is that either you were using CVF and not Intel Fortran for your IA-32 builds, or that you have different project settings between IA-32 and Intel 64. If you deliberately changed the /iface setting on the 64-bit project because the documentation said it was not supported, then that would cause the problem you saw. You chose the solution I would prefer - making the C code match the Intel defaults, but you could also have used matching project options (including /iface:cvf) for both 32 and 64-bit builds and it should also have worked that way.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks very much for the clarification.
I have created a small test problem that shows the problem we are having. The test problem is a main C++ progam that calls a simple FORTRAN routine and passes a few ints and 2 characters to the FORTRAN. We use a CHARACTER class that handles the (char *, length value) pairings. This class works fine on win32 and several other platforms (such as linux 32 and 64, AIX etc).
If the code is built with VC2005/Intel 10 in 32bit it works fine as one would expect. If the same code is built with 64bit (no changes apart from switching to 64bit compile options), then the fortran subroutine crashes because the strings are corrupted. This leads me to think that there might be a bugin the Intel 64bit CVF string handling.
I have added the code below but can send you the VC2005 projects (for the C++ and FORTRAN) if you give me an email address.
Any advice is most appreciated.
Thank you!
Tony
// Calling.cpp : Defines the entry point for the console application.
//
#include
"stdafx.h"#include
#include
#include
class
CHARACTER{
// // Trick to force compile-time errors on any attempt to copy or assign. // Note: DO NOT WRITE THESE, LET THE COMPILER AND LINKER FIND THESE // ILLEGAL ACTIONS FOR YOU! THIS IS INTENTIONAL! //CHARACTER&
operator=( const CHARACTER& rhs ); // assignment operatorpublic
:CHARACTER(
char* cstring);~CHARACTER();
operator char*();public
: char* rep; // Actual stringsize_t len;
// String length};
CHARACTER::CHARACTER(
char* cstring) :rep(cstring),
len(strlen(cstring))
{ }
CHARACTER::~CHARACTER()
{
}
CHARACTER::
operator char*(){
return}
extern
"C" void __stdcall SUB(int& int1, int &, CHARACTER , CHARACTER , int &);int
_tmain(int argc, _TCHAR* argv[]){
// Calling convention testprintf(
"Calling FORTRAN... "); int int1=1; int int2=2; int int3=3; char* string1 = "I am the first string"; char* string2 = "I am the second string";SUB(int1,int2,string1,string2,int3);
return 0;}
subroutine sub(int1, int2, string1, string2, int3) implicit none integer int1, int2, int3 character*(*) string1, string2C
write(6,*) int1,int2,int3 write(6,*) string1, string2C
return end- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I should have added that we are compiling with /iface:cvf for this project.
Tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I will note that the use of "int" for the character lengths could be a problem - you should use size_t instead.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We are using t_size to hold the string lengths, which I believe should work on 64bit?
Thank you for trying out the code - I will be very interested to hear your conclusions.
Tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As best as I can tell, the Fortran code is fine on x64. I built a Fortran equivalent of your C++ routine to pass the string addresses and lengths in the proper places, and it worked fine when built with /iface:cvf on x64.
Your C++ code, though, is doing something very bad on x64.. To show this, I first modified the Fortran code so that there were seven integer arguments and printed the locations of each.. I expect to see reasonable "address-looking" numbers for the integer and string address arguments, and to see 64-bit smallish integer values for the lengths. What I get however is this:
2358804 2358836 2358960
2358976 2358868 -3689348814741910324
7730941132
The first five look like addresses, but they shouldn't all be - the fourth value should be the length of string1.
I then looked to see what data was at these addresses (four bytes for the integers and 8 for the others) and got this:
00000001 00000002 0000000140117E38 0000000140117E50 CCCCCCCC00000003
int1 and int2 are ok. Darned if I know what the next two are - the first ought to be the data bytes of string1, but clearly is an address of some kind, as is the second one. The fifth entry appears to be partially uninitialized storage and might be just int3 (with unallocated bytes displayed.)
I'm not a C++ expert so I'll have to leave it to you to figure out what it is doing wrong.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks so much for your reply - Ill take a look at the C++. Its good to know that the compiler supports CVF calling convention for 64bit - its just a case now of figuring out whats wrong with our C++.
thank you again,
Tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Steve,
Thanks for testing CVF works for Fortran calling Fortran on 64bit, but isnt the main use case of the calling convention that you want it for C++ calling Fortran? I see there is a sample that comes with the compiler, but that isnt using CVF, but it does give me the idea that perhaps our problem is that we arent using INTERFACE.
thanks
tony
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The problem you're having is NOT on the Fortran side - that's working perfectly. It's the C++ code that is passing garbage in the x64 case. I don't lnow what MSVC does with __STDCALL on x64, but I think the problems are elsewhere, since arguments are being passed incorrectly (and __STDCALL affects stack cleanup after the call.)
INTERFACE won't help C++.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page