- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have a C pointer that points to a memory buffer that I am trying to map to a common block in FORTRAN. As a simple example let assume I have this,
char buf[100];
__declspec (dllexport) char *xrftest = buf;
I am trying to mapa common block to the pointer. Let say this:
integer*4
& F2
&, F1
CHARACTER*1
& DUM(80)
COMMON /BOB /
& DUM, F1, F2
Is there a way to bring in the pointer and do an equivalence or something to map the memory to the common block?
Here is what I tried with no success:
!ms$attributes dllimport :: XRFTEST
!ms$attributes C, alias : '_xrftest' :: XRFTEST
EQUIVALENCE(BOB, XRFTEST)
Thanks
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have a C pointer that points to a memory buffer that I am trying to map to a common block in FORTRAN.
You'd have to follow the traditional examples, using the labeled COMMON name on the Fortran side as a global struct on the C side, Even if you don't care to use modern alternatives, you should read the "Interoperability with C" section of ifort documentation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You'd have to follow the traditional examples, using the labeled COMMON name on the Fortran side as a global struct on the C side, Even if you don't care to use modern alternatives, you should read the "Interoperability with C" section of ifort documentation.
Usually, this works if you access the buffer straight:
Something like,
integer*4
& F2
&, F1
CHARACTER*1
& DUM(80)
COMMON /XRFTEST/
& DUM, F1, F2
!ms$attributes dllimport :: XRFTEST
!ms$attributes C, alias : '_xrftest' :: XRFTEST
Where XRFTEST is now the buffer char XRFTEST[100];
however, this does not function with a pointer to bytes in memory.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The tricky part here is that the C object is a pointer to a thing, not the thing itself. While this can be done with various extensions, let me show you how it's done in standard Fortran 2003:
[cpp] module mymod use, intrinsic :: ISO_C_BINDING implicit none type, bind(C) :: xrftest_t character(80) :: DUM integer(C_INT) :: F1, F2 end type xrftest_t type(C_PTR), bind(C) :: xrftest end module mymod program test use mymod type(xrftest_t), pointer :: BOB ! Convert C pointer to Fortran pointer call c_f_pointer (xrftest, BOB) print *, BOB%DUM end program test [/cpp]
It is required that the declaration of the "interoperable variable" (the one you're sharing with C) be in a module, so I've put the structure declaration and the variable in a module. Note the bind(C) on the type and variable - these tell the compiler that these items are "interoperable".
The main program uses C_F_POINTER (inherited from ISO_C_BINDING) to convert the C pointer to a Fortran pointer (of type xrftest_t). Now you can reference the components of the structure.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The tricky part here is that the C object is a pointer to a thing, not the thing itself. While this can be done with various extensions, let me show you how it's done in standard Fortran 2003:
module mymod use, intrinsic :: ISO_C_BINDING implicit none type, bind(C) :: xrftest_t character(80) :: DUM integer(C_INT) :: F1, F2 end type xrftest_t type(C_PTR), bind(C) :: xrftest end module mymod program test use mymod type(xrftest_t), pointer :: BOB ! Convert C pointer to Fortran pointer call c_f_pointer (xrftest, BOB) print *, BOB%DUM end program test
It is required that the declaration of the "interoperable variable" (the one you're sharing with C) be in a module, so I've put the structure declaration and the variable in a module. Note the bind(C) on the type and variable - these tell the compiler that these items are "interoperable".
The main program uses C_F_POINTER (inherited from ISO_C_BINDING) to convert the C pointer to a Fortran pointer (of type xrftest_t). Now you can reference the components of the structure.
The problem I have is that I want to be able to access the variables DUM, F1, and F2 straight without pointers. This is because I don't want to change existing code that I have. If there a way not to use pointer notation?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, you mean component notation - there's no pointer there. Here's an alternative. It still involves pointers but once you call init at the beginning of the program, the rest of your code can reference DUM, F1 and F2 directly. All you have to do is add the USE of the module to make them visible.
[cpp] module mymod use, intrinsic :: ISO_C_BINDING implicit none type, bind(C):: xrftest_t character(80) :: DUM integer(C_INT) :: F1, F2 end type xrftest_t type(C_PTR), bind(C) :: xrftest character(80), pointer, protected :: DUM integer(C_INT), pointer, protected :: F1, F2 contains subroutine init type(xrftest_t), pointer :: p call c_f_pointer (xrftest, p) DUM => p%DUM F1 => p%F1 F2 => p%f2 end subroutine init end module mymod program test use mymod call init print *, F1 end program test[/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, you mean component notation - there's no pointer there. Here's an alternative. It still involves pointers but once you call init at the beginning of the program, the rest of your code can reference DUM, F1 and F2 directly. All you have to do is add the USE of the module to make them visible.
module mymod use, intrinsic :: ISO_C_BINDING implicit none type, bind(C):: xrftest_t character(80) :: DUM integer(C_INT) :: F1, F2 end type xrftest_t type(C_PTR), bind(C) :: xrftest character(80), pointer, protected :: DUM integer(C_INT), pointer, protected :: F1, F2 contains subroutine init type(xrftest_t), pointer :: p call c_f_pointer (xrftest, p) DUM => p%DUM F1 => p%F1 F2 => p%f2 end subroutine init end module mymod program test use mymod call init print *, F1 end program test
I assume that all of this is only in 10.1. Do you have a equivalent for 9.1?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The tricky part here is that the C object is a pointer to a thing, not the thing itself. While this can be done with various extensions, let me show you how it's done in standard Fortran 2003:
module mymod use, intrinsic :: ISO_C_BINDING implicit none type, bind(C) :: xrftest_t character(80) :: DUM integer(C_INT) :: F1, F2 end type xrftest_t type(C_PTR), bind(C) :: xrftest end module mymod program test use mymod type(xrftest_t), pointer :: BOB ! Convert C pointer to Fortran pointer call c_f_pointer (xrftest, BOB) print *, BOB%DUM end program test
It is required that the declaration of the "interoperable variable" (the one you're sharing with C) be in a module, so I've put the structure declaration and the variable in a module. Note the bind(C) on the type and variable - these tell the compiler that these items are "interoperable".
The main program uses C_F_POINTER (inherited from ISO_C_BINDING) to convert the C pointer to a Fortran pointer (of type xrftest_t). Now you can reference the components of the structure.
Is there a way to do the assignment "call c_f_pointer (xrftest, BOB)" in a global scope? The reason I ask is becuase all my declaration for the legacy code is inside an include file so as I am generating the include file, I have problems accessing the FORTRAN file.
I guess I need the equivalence of doing something like this in a C header?
int getValue() {return 1}
int a = getValue();
a will be assigned 1 when you load (global scope)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No - Fortran doesn't have that sort of thing. What you can do is write an initialization procedure that does the conversion and call it at the start of the main program (or wherever is convenient.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, here I go again trying to do the same thing but a different way. Basically, I am trying to create a filemappingand I am trying to map given variables to vars that already exist. I saw another approach that was like:
[cpp] COMMON /XRFTEST / dummy(0:99) !ms$attributes dllimport :: XRFTEST !ms$attributes C, alias : '_xrftest' :: xrftest CHARACTER*1 dummy INTEGER*4 ABC Equivalence(ABC, dummy(80)) ABC = 99[/cpp]that seems to work fine when I had
__declspec (dllexport) char xrftest[100];
but because I am only getting a pointer back when I use the file mapping, this does not work with
__declspec (dllexport) char buf[100];
__declspec (dllexport) char *xrftest = buf;
Any idea how to map existing vars in the declaration area like the above? It would be nice if the import would force dummy to use the same memory as XRFTEST which is noe a pointer.
I'm not sure if the following is a clue to make it easier, but creating a common block pointing to a big chuck of memory and doing equivalence was much easier because I didn't have to do any assignments, just declarations. Also, I didn't require any code change to my legacy code. The worst case for me is to have to create a parser to format all of the legacy code that I have.
Perhaps there is an easier way to map shared memory in FORTRAN?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You now want to provide/change the values held in that common block by manipulating a buffer in some C code (to be linked into the Fortran code via a .LIB created from the C code?)
Why not just declare XRFTEST as External in the C code and you can play with it there at your leisure?
#define BUFFLEN 80
extern "C" double XRFTEST_mp_BYTES[BUFFLEN];
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The problem is we use to do shared memory in C using what you have stated above. Here is what we had
__declspec (dllexport) char xrftest[SEG0SIZE]
And then to create a shared memory we would do:
#pragma data_seg()
#pragma comment(linker, "-section:.CDB,rws")
This worked great for accessing variables in C++ using structures and in FORTRAN using common blocks and mapping using the above method.
The problem now is that Vista came along and you can no longer use the above method to create shared memory. This type of shared memory does not work across user sessions. Therfore, now I have to use CreateFileMapping with a security descriptor to create the shared memory.
Using this way to create the shared memory, xrftest is no longer an array. It is just a pointer I get back using MapViewOfFile.
In C++ you can do the following to access the same array
extern "C" __declspec (dllimport) char *xrftest;
struct cdb_xrftest {
unsigned char dum[80];
int ABC;
};
static struct cdb_xrftest &xrftest_ptr = (struct cdb_xrftest &)*xrftest;
#defineABC xrftest_ptr.ABC
Yuo can even do the following:
static struct cdb_xrftest *xrftest_ptr = (struct cdb_xrftest *)xrftest;
#define ABC xrftest_ptr->ABC
How can this be done in FORTRAN? Is there a way to map the xrftest pointer to the common block?
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page