- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm porting some HP-UX code and have hit a snag with a construct that seemed ok on the Unix boxes but causes me nothing but trouble with Visual Fortran.
Here's a snippet of what's causing me trouble:
logical function parse( a, b, c, d, e )
integer*4 a,d
character*(*) b
logical e
call access_dataf( a, b, c, d, e )
access_dataf is a C routine, and its the second parameter that's the problem. Its declared as a void ** and the variable length character parameter got me the right type of arbitrary pointer to pointer on HP-UX, but what can I use with Visual Fortran?
access_dataf is a general data reading function, returning real, int, string, etc.
Or will I end up needing to write a access_data_int and access_data_real and access_data_int_array and access_data_real_array and ...?
I thought I was on the right track with the !DEC$ ATTRIBUTES REFERENCE :: variable_name, but I'm not allowed to use that on variable length strings.
Here's a snippet of what's causing me trouble:
logical function parse( a, b, c, d, e )
integer*4 a,d
character*(*) b
logical e
call access_dataf( a, b, c, d, e )
access_dataf is a C routine, and its the second parameter that's the problem. Its declared as a void ** and the variable length character parameter got me the right type of arbitrary pointer to pointer on HP-UX, but what can I use with Visual Fortran?
access_dataf is a general data reading function, returning real, int, string, etc.
Or will I end up needing to write a access_data_int and access_data_real and access_data_int_array and access_data_real_array and ...?
I thought I was on the right track with the !DEC$ ATTRIBUTES REFERENCE :: variable_name, but I'm not allowed to use that on variable length strings.
Link Copied
7 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's not all clear to me. First, why void** (why not just void*)? Void** would be required if access_dataf allocates memory (or changes the address) for the argument b -- does it? Second, which argument is of variant type? Can you post some code of access_dataf an some original HP-UX calling code?
Jugoslav
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oops typo on my part, I didn't notice I wrote void **, it should just be void *. My problem still occurs, I want a way from Fortran to call C with an arbitrary pointer to anything. On HP-UX, I could use the variable length character mechanism to get this, even if the actual parameter was a real or an int.
With the VF compiler, it complains, and I need a way to pass the address (which is the default in Fortran I thought) of actual parameters of differing types.
With the VF compiler, it complains, and I need a way to pass the address (which is the default in Fortran I thought) of actual parameters of differing types.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
LOC() (or %LOC()) function returns the address of the argument. There are several ways to do what you want:
1) Enclose all actual arguments into LOC(). It's simplest, but it sounds like a cludge to me.
2) Leave the calling source as-is. Create a header file (include or module) containing generic interface for the C function, with different types of argument b, but all physically mapped to the same C function:
3) Similar to 2), except that it's most portable and all Fortran. Rewrite access_dataf into several Fortran routines access_data_int etc. Place it in a module and define a generic interface (no changes to rest of the code except having to USE that module wherever required):
1) Enclose all actual arguments into LOC(). It's simplest, but it sounds like a cludge to me.
2) Leave the calling source as-is. Create a header file (include or module) containing generic interface for the C function, with different types of argument b, but all physically mapped to the same C function:
interface access_dataf subroutine access_data_string(a,b,c,d,e) !DEC$ATTRIBUTES C, ALIAS: "_access_dataf" :: access_data_real !DEC$ATTRIBUTES REFERENCE: b !suppress passing length integer a character(*) b whatever c, d, e end subroutine access_data_string !---- subroutine access_data_int(a,b,c,d,e) !DEC$ATTRIBUTES C, ALIAS: "_access_dataf" :: access_data_int !DEC$ATTRIBUTES REFERENCE: b !call by reference integer a integer b ... end subroutine access_data_int !---- subroutine access_data_real(a,b,c,d,e) !... end subroutine access_data_real end interface access_datafThe same technique is used occasionally in CVF headers. Look for "interface qsort" in ...DF98IncludeDFPORT.f90. Of course, you'll have to INCLUDE that file or USE that module wherever required.
3) Similar to 2), except that it's most portable and all Fortran. Rewrite access_dataf into several Fortran routines access_data_int etc. Place it in a module and define a generic interface (no changes to rest of the code except having to USE that module wherever required):
module m_access interface access_dataf module procedure access_data_real module procedure access_data_int module procedure access_data_string end interface !------------ contains !------------ subroutine access_data_real(a, b, c, d, e) !...code of access_data_real here end subroutine access_data_real !------------------------------- subroutine access_data_int(... ... end subroutine access_data_string !------------------------------- end module m_accessJugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, I actually use a #define:
#define PARSE(a, b, c, d, e ) if( parse( a, LOC( b ), c, e, d ) ) goto 999
So I just added the LOC to the #define, looks like that will do the trick, thanks!
#define PARSE(a, b, c, d, e ) if( parse( a, LOC( b ), c, e, d ) ) goto 999
So I just added the LOC to the #define, looks like that will do the trick, thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, now I'm just plain stumped.
I used the define based on what you said. I've compiled, but when I like I'm told missing symbol PARSE@20. Why would the compiler think the function either 1) Only has 4 parameters and a return value, or 2) has 5 parameters and no return value?
Seems pretty obvious to me that parse returns a value, because I've got a
logical parse
in the Fortran when my #define is used, and that there are 5 parameters to the call, so why is the object being produced looking for PARSE@20?
Please help clue me in.
Thanks
I used the define based on what you said. I've compiled, but when I like I'm told missing symbol PARSE@20. Why would the compiler think the function either 1) Only has 4 parameters and a return value, or 2) has 5 parameters and no return value?
Seems pretty obvious to me that parse returns a value, because I've got a
logical parse
in the Fortran when my #define is used, and that there are 5 parameters to the call, so why is the object being produced looking for PARSE@20?
Please help clue me in.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Return value (at least scalar one) doesn't count in number of arguments, so, _PARSE@20 is OK...
...but you didn't adjust calling conventions right; I was a bit surprised that LOC solution worked immediately without INTERFACE block, which you didn't mention, so I assumed it was there.
Default calling convention in CVF is stdcall, which produces symbols like _PARSE@20. Default calling convention in MSVC++ (is that what you used to compile C code?) is cdecl; it produces symbols like _parse. Calling conventions must match. On HP-UX there's only cdecl for both Fortran and C (and cdecl is and will be the default in Intel Fortran), so there are no problems.
One solution is to make an interface for parse:
Jugoslav
...but you didn't adjust calling conventions right; I was a bit surprised that LOC solution worked immediately without INTERFACE block, which you didn't mention, so I assumed it was there.
Default calling convention in CVF is stdcall, which produces symbols like _PARSE@20. Default calling convention in MSVC++ (is that what you used to compile C code?) is cdecl; it produces symbols like _parse. Calling conventions must match. On HP-UX there's only cdecl for both Fortran and C (and cdecl is and will be the default in Intel Fortran), so there are no problems.
One solution is to make an interface for parse:
interface logical function Parse(a, b, c, d, e) !dec$attributes C:: parse integer:: a integer:: b whatever:: c, d, e end function end interfaceAnother solution is to compile Fortran code with "C, by reference" calling convention (/iface:cref). Yet another is to declare parse __stdcall in C code (if the file has extension .cpp, you have to use extern "C" as well:
extern "C" bool __stdcall PARSE(a, b, c, d, e)If you use interface, take care to add !dec$attributes reference:: c for every argument which is a pointer -- but not for b, since LOC() already adds one level of indirection.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, Jugoslav, for excellent explanations. Since IFL has been mentioned in passing, I'll note that /iface:cref will not be supported until the 8.0 release. IFL 7.1 should support the other features mentioned, but I have an Intel Premier issue filed on a problem with use of /Gz (__stdcall) in a case much like this.

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